Filtrage avec DataView (LINQ to DataSet)

La possibilité de filtrer des données à l’aide de critères spécifiques, puis de présenter les données à un client via un contrôle d’interface utilisateur est un aspect important de la liaison de données. DataView fournit plusieurs façons de filtrer les données et de retourner des sous-ensembles de lignes de données répondant à des critères de filtre spécifiques. Outre les fonctionnalités de filtrage basées sur des chaînes, DataView fournit également la possibilité d’utiliser des expressions LINQ pour les critères de filtrage. Les expressions LINQ permettent d’effectuer des opérations de filtrage beaucoup plus complexes et puissantes que le filtrage basé sur des chaînes.

Il existe deux façons de filtrer les données à l’aide d’un DataView:

  • Créer une DataView à partir d’une requête LINQ to DataSet avec une clause Where.

  • Utilisez les fonctionnalités de filtrage basées sur des chaînes existantes de DataView.

Création de DataView à partir d’une requête avec des informations de filtrage

Un DataView objet peut être créé à partir d’une requête LINQ to DataSet. Si cette requête contient une Where clause, DataView est créée avec les informations de filtrage de la requête. L’expression de la Where clause est utilisée pour déterminer les lignes de données qui seront incluses dans le DataViewfiltre et constitue la base du filtre.

Les filtres basés sur des expressions offrent un filtrage plus puissant et plus complexe que les filtres basés sur des chaînes plus simples. Les filtres basés sur des chaînes et basés sur des expressions s’excluent mutuellement. Lorsque la chaîne RowFilter est définie après la création d’une DataView requête, le filtre basé sur l’expression déduit de la requête est effacé.

Remarque

Dans la plupart des cas, les expressions utilisées pour le filtrage ne doivent pas avoir d’effets secondaires et doivent être déterministes. En outre, les expressions ne doivent pas contenir de logique qui dépend d’un nombre défini d’exécutions, car les opérations de filtrage peuvent être exécutées n’importe quel nombre de fois.

Exemple :

L’exemple suivant interroge la table SalesOrderDetail pour les commandes dont la quantité est supérieure à 2 et inférieure à 6 ; crée une DataView requête à partir de cette requête ; et lie l’objet DataView à un BindingSource:

DataTable orders = _dataSet.Tables["SalesOrderDetail"];

EnumerableRowCollection<DataRow> query = from order in orders.AsEnumerable()
                                         where order.Field<short>("OrderQty") > 2 && order.Field<short>("OrderQty") < 6
                                         select order;

DataView view = query.AsDataView();

bindingSource1.DataSource = view;
Dim orders As DataTable = dataSet.Tables("SalesOrderDetail")

Dim query = _
    From order In orders.AsEnumerable() _
    Where order.Field(Of Int16)("OrderQty") > 2 And _
          order.Field(Of Int16)("OrderQty") < 6 _
    Select order

Dim view As DataView = query.AsDataView()
bindingSource1.DataSource = view

Exemple :

L’exemple suivant crée un DataView à partir d'une requête pour les commandes passées après le 6 juin 2001 :

DataTable orders = _dataSet.Tables["SalesOrderHeader"];

EnumerableRowCollection<DataRow> query = from order in orders.AsEnumerable()
                                         where order.Field<DateTime>("OrderDate") > new DateTime(2002, 6, 1)
                                         select order;

DataView view = query.AsDataView();

bindingSource1.DataSource = view;
Dim orders As DataTable = dataSet.Tables("SalesOrderHeader")

Dim query = _
    From order In orders.AsEnumerable() _
    Where order.Field(Of DateTime)("OrderDate") > New DateTime(2002, 6, 1) _
    Select order

Dim view As DataView = query.AsDataView()
bindingSource1.DataSource = view

Exemple :

Le filtrage peut également être combiné avec le tri. L'exemple suivant crée un DataView à partir d'une requête pour les contacts dont le nom de famille commence par "S" et triés par nom de famille, puis par prénom :

DataTable contacts = _dataSet.Tables["Contact"];

EnumerableRowCollection<DataRow> query = from contact in contacts.AsEnumerable()
                                         where contact.Field<string>("LastName").StartsWith("S")
                                         orderby contact.Field<string>("LastName"), contact.Field<string>("FirstName")
                                         select contact;

DataView view = query.AsDataView();

bindingSource1.DataSource = view;
dataGridView1.AutoResizeColumns();

Dim contacts As DataTable = dataSet.Tables("Contact")

Dim query = _
    From contact In contacts.AsEnumerable() _
    Where contact.Field(Of String)("LastName").StartsWith("S") _
    Order By contact.Field(Of String)("LastName"), contact.Field(Of String)("FirstName") _
    Select contact

Dim view As DataView = query.AsDataView()
bindingSource1.DataSource = view
dataGridView1.AutoResizeColumns()

Exemple :

L’exemple suivant utilise l’algorithme SoundEx pour rechercher des contacts dont le nom est similaire à « Zhu ». L’algorithme SoundEx est implémenté dans la méthode SoundEx.

DataTable contacts = _dataSet.Tables["Contact"];

var soundExCode = SoundEx("Zhu");

EnumerableRowCollection<DataRow> query = from contact in contacts.AsEnumerable()
                                         where SoundEx(contact.Field<string>("LastName")) == soundExCode
                                         select contact;

DataView view = query.AsDataView();

bindingSource1.DataSource = view;
dataGridView1.AutoResizeColumns();
Dim contacts As DataTable = dataSet.Tables("Contact")
Dim soundExCode As String = SoundEx("Zhu")

Dim query = _
    From contact In contacts.AsEnumerable() _
    Where SoundEx(contact.Field(Of String)("LastName")) = soundExCode _
    Select contact

Dim view As DataView = query.AsDataView()
bindingSource1.DataSource = view
dataGridView1.AutoResizeColumns()

SoundEx est un algorithme phonétique utilisé pour l’indexation des noms par son, car ils sont prononcés en anglais, initialement développé par le Bureau de recensement des États-Unis. La méthode SoundEx retourne un code de quatre caractères pour un nom composé d’une lettre anglaise suivie de trois nombres. La lettre est la première lettre du nom et les chiffres encodent les consonnes restantes dans le nom. Les noms de sons similaires partagent le même code SoundEx. L’implémentation SoundEx utilisée dans la méthode SoundEx de l’exemple précédent est illustrée ici :

static string SoundEx(string word)
{
    // The length of the returned code.
    const int length = 4;

    // Value to return.
    var value = "";

    // The size of the word to process.
    var size = word.Length;

    // The word must be at least two characters in length.
    if (size > 1)
    {
        // Convert the word to uppercase characters.
        word = word.ToUpper(CultureInfo.InvariantCulture);

        // Convert the word to a character array.
        var chars = word.ToCharArray();

        // Buffer to hold the character codes.
        var buffer = new StringBuilder
        {
            Length = 0
        };

        // The current and previous character codes.
        var prevCode = 0;
        var currCode = 0;

        // Add the first character to the buffer.
        buffer.Append(chars[0]);

        // Loop through all the characters and convert them to the proper character code.
        for (var i = 1; i < size; i++)
        {
            switch (chars[i])
            {
                case 'A':
                case 'E':
                case 'I':
                case 'O':
                case 'U':
                case 'H':
                case 'W':
                case 'Y':
                    currCode = 0;
                    break;
                case 'B':
                case 'F':
                case 'P':
                case 'V':
                    currCode = 1;
                    break;
                case 'C':
                case 'G':
                case 'J':
                case 'K':
                case 'Q':
                case 'S':
                case 'X':
                case 'Z':
                    currCode = 2;
                    break;
                case 'D':
                case 'T':
                    currCode = 3;
                    break;
                case 'L':
                    currCode = 4;
                    break;
                case 'M':
                case 'N':
                    currCode = 5;
                    break;
                case 'R':
                    currCode = 6;
                    break;
            }

            // Check if the current code is the same as the previous code.
            if (currCode != prevCode)
            {
                // Check to see if the current code is 0 (a vowel); do not process vowels.
                if (currCode != 0)
                {
                    buffer.Append(currCode);
                }
            }
            // Set the previous character code.
            prevCode = currCode;

            // If the buffer size meets the length limit, exit the loop.
            if (buffer.Length == length)
            {
                break;
            }
        }
        // Pad the buffer, if required.
        size = buffer.Length;
        if (size < length)
        {
            buffer.Append('0', length - size);
        }

        // Set the value to return.
        value = buffer.ToString();
    }
    // Return the value.
    return value;
}
Private Function SoundEx(ByVal word As String) As String

    Dim length As Integer = 4
    ' Value to return
    Dim value As String = ""
    ' Size of the word to process
    Dim size As Integer = word.Length
    ' Make sure the word is at least two characters in length
    If (size > 1) Then
        ' Convert the word to all uppercase
        word = word.ToUpper(System.Globalization.CultureInfo.InvariantCulture)
        ' Convert the word to character array for faster processing
        Dim chars As Char() = word.ToCharArray()
        ' Buffer to build up with character codes
        Dim buffer As StringBuilder = New StringBuilder()
        ' The current and previous character codes
        Dim prevCode As Integer = 0
        Dim currCode As Integer = 0
        ' Append the first character to the buffer
        buffer.Append(chars(0))
        ' Loop through all the characters and convert them to the proper character code
        For i As Integer = 1 To size - 1
            Select Case chars(i)

                Case "A", "E", "I", "O", "U", "H", "W", "Y"
                    currCode = 0

                Case "B", "F", "P", "V"
                    currCode = 1

                Case "C", "G", "J", "K", "Q", "S", "X", "Z"
                    currCode = 2

                Case "D", "T"
                    currCode = 3

                Case "L"
                    currCode = 4

                Case "M", "N"
                    currCode = 5

                Case "R"
                    currCode = 6
            End Select

            ' Check to see if the current code is the same as the last one
            If (currCode <> prevCode) Then

                ' Check to see if the current code is 0 (a vowel); do not process vowels
                If (currCode <> 0) Then
                    buffer.Append(currCode)
                End If
            End If
            ' Set the new previous character code
            prevCode = currCode
            ' If the buffer size meets the length limit, then exit the loop
            If (buffer.Length = length) Then
                Exit For
            End If
        Next
        ' Pad the buffer, if required
        size = buffer.Length
        If (size < length) Then
            buffer.Append("0", (length - size))
        End If
        ' Set the value to return
        value = buffer.ToString()
    End If
    ' Return the value
    Return value
End Function

Utilisation de la propriété RowFilter

La fonctionnalité existante de filtrage basé sur des chaînes de DataView fonctionne néanmoins toujours dans le contexte de LINQ to DataSet. Pour plus d’informations sur le filtrage basé sur RowFilter des chaînes, consultez Tri et Filtrage des données.

L’exemple suivant crée une DataView à partir de la table Contact, puis définit la RowFilter propriété pour renvoyer les lignes où le nom du contact est « Zhu » :

DataTable contacts = _dataSet.Tables["Contact"];

DataView view = contacts.AsDataView();

view.RowFilter = "LastName='Zhu'";

bindingSource1.DataSource = view;
dataGridView1.AutoResizeColumns();
Dim contacts As DataTable = dataSet.Tables("Contact")

Dim view As DataView = contacts.AsDataView()
view.RowFilter = "LastName='Zhu'"
bindingSource1.DataSource = view
dataGridView1.AutoResizeColumns()

Une fois qu'une DataView a été créée à partir d'un DataTable ou d'une requête LINQ to DataSet, vous pouvez utiliser la propriété RowFilter pour spécifier des sous-ensembles de lignes en fonction de leurs valeurs de colonne. Les filtres basés sur des chaînes et basés sur des expressions s’excluent mutuellement. La définition de la RowFilter propriété efface l’expression de filtre déduite de la requête LINQ to DataSet, et l’expression de filtre ne peut pas être réinitialisée.

DataTable contacts = _dataSet.Tables["Contact"];

EnumerableRowCollection<DataRow> query = from contact in contacts.AsEnumerable()
                                         where contact.Field<string>("LastName") == "Hernandez"
                                         select contact;

DataView view = query.AsDataView();

bindingSource1.DataSource = view;
dataGridView1.AutoResizeColumns();

view.RowFilter = "LastName='Zhu'";
Dim contacts As DataTable = dataSet.Tables("Contact")

Dim query = _
    From contact In contacts.AsEnumerable() _
    Where contact.Field(Of String)("LastName") = "Hernandez" _
    Select contact

Dim view As DataView = query.AsDataView()
bindingSource1.DataSource = view

dataGridView1.AutoResizeColumns()
view.RowFilter = "LastName='Zhu'"

Si vous souhaitez retourner les résultats d’une requête particulière sur les données, plutôt que de fournir une vue dynamique d’un sous-ensemble des données, vous pouvez utiliser les méthodes Find ou FindRows de la DataView, plutôt que de définir la propriété RowFilter. La RowFilter propriété est la meilleure utilisée dans une application liée aux données où un contrôle lié affiche des résultats filtrés. La définition de la RowFilter propriété reconstruit l’index pour les données, en ajoutant une surcharge à votre application et en réduisant les performances. Les méthodes Find et FindRows utilisent l’index actuel sans nécessiter la reconstruction de l’index. Si vous allez appeler Find ou FindRows une seule fois, vous devez utiliser l’existant DataView. Si vous allez appeler Find ou FindRows plusieurs fois, vous devez créer un nouveau DataView pour reconstruire l’index de la colonne de recherche, puis appeler les méthodes Find ou FindRows. Pour plus d'informations sur les méthodes Find et FindRows, consultez Recherche de lignes et Performance DataView.

Effacement du filtre

Le filtre sur un DataView peut être effacé une fois le filtrage défini à l’aide de la RowFilter propriété. Le filtre sur un DataView peut être effacé de deux façons différentes :

  • Attribuez à la propriété RowFilter la valeur null.

  • Définissez la RowFilter propriété sur une chaîne vide.

Exemple :

L'exemple suivant crée un DataView à partir d'une requête, puis efface le filtre en définissant la propriété RowFilter sur null :

DataTable orders = _dataSet.Tables["SalesOrderHeader"];

EnumerableRowCollection<DataRow> query = from order in orders.AsEnumerable()
                                         where order.Field<DateTime>("OrderDate") > new DateTime(2002, 11, 20)
                                            && order.Field<decimal>("TotalDue") < new decimal(60.00)
                                         select order;

DataView view = query.AsDataView();

bindingSource1.DataSource = view;

view.RowFilter = null;
Dim orders As DataTable = dataSet.Tables("SalesOrderHeader")

Dim query = _
    From order In orders.AsEnumerable() _
    Where order.Field(Of DateTime)("OrderDate") > New DateTime(2002, 11, 20) _
        And order.Field(Of Decimal)("TotalDue") < New Decimal(60.0) _
    Select order

Dim view As DataView = query.AsDataView()
bindingSource1.DataSource = view
view.RowFilter = Nothing

Exemple :

L'exemple suivant crée un DataView à partir d'une table, définit la propriété RowFilter, puis supprime le filtre en définissant la propriété RowFilter en tant que chaîne vide :

DataTable contacts = _dataSet.Tables["Contact"];

DataView view = contacts.AsDataView();

view.RowFilter = "LastName='Zhu'";

bindingSource1.DataSource = view;
dataGridView1.AutoResizeColumns();

// Clear the row filter.
view.RowFilter = "";
Dim contacts As DataTable = dataSet.Tables("Contact")

Dim view As DataView = contacts.AsDataView()
view.RowFilter = "LastName='Zhu'"
bindingSource1.DataSource = view
dataGridView1.AutoResizeColumns()

' Clear the row filter.
view.RowFilter = ""

Voir aussi