Partager via


Filtrage avec DataView (LINQ to DataSet)

La possibilité de filtrer des données en utilisant des critères spécifiques, puis de les présenter à un client à travers un contrôle d’interface utilisateur, est un important aspect de la liaison de données. DataView propose plusieurs manières de filtrer les données et de retourner des sous-ensembles de lignes de données correspondant à des critères de filtre spécifiques. Outre les capacités de filtrage basé sur des chaînes, DataView donne également la possibilité d’utiliser des expressions LINQ pour les critères de filtrage. Les expressions LINQ permettent 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 des données à l'aide d'un DataView :

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

  • Utiliser les fonctionnalités de filtrage basé sur chaîne existantes de DataView.

Création d'un DataView à partir d'une requête avec informations de filtrage

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

Les filtres basés sur une expression offrent une filtrage plus puissant et plus complexe que les filtres basés sur chaîne. Les filtres basés sur chaîne et sur une expression s'excluent mutuellement. Lorsque le RowFilter basé sur chaîne est défini après la création d'un DataView à partir d'une requête, le filtre basé sur une expression déduit de la requête est supprimé.

Notes

Dans la plupart des cas, les expressions utilisées pour le filtrage ne doivent pas avoir d'effets secondaires et doivent être déterministes. De plus, les expressions ne doivent pas contenir de logique dépendant d'un nombre défini d'exécutions, parce que les opérations de filtrage doivent pouvoir être exécutées de façon illimitée.

Exemple

L'exemple suivant interroge la table SalesOrderDetail pour extraire les commandes de quantité supérieure à 2 et inférieure à 6 ; crée un DataView à partir de cette requête, et lie le DataView à une 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 correspondant aux 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 commence par la lettre « S » et trié par nom, 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 semblable à « 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 qui sert à indexer les nom par son, tels qu'ils sont prononcés en anglais, qui a été développé à l'origine par le Bureau du recensement des États-Unis. La méthode SoundEx retourne un code à quatre caractères pour un nom comprenant une lettre alphabétique suivie de trois chiffres. La lettre est la première du nom et les chiffres encodent les consonnes restantes du nom. Les noms de consonance similaire ont 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 RowFilter basé sur des chaînes, consultez Tri et filtrage des données.

L'exemple suivant crée une table DataView à partir de la table Contact, puis définit la propriété RowFilter pour retourner 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’une requête 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 des valeurs de leurs colonnes. Les filtres basés sur chaîne et sur une expression s'excluent mutuellement. La définition de la propriété RowFilter va effacer l’expression de filtre inférée de la requête LINQ to DataSet, l’expression de filtre ne pouvant 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 exécutée sur les données, vous pouvez, au lieu de fournir une vue dynamique d'un sous-ensemble des données, utiliser l'une des méthodes Find ou FindRows du DataView, plutôt que de définir la propriété RowFilter. L'utilisation de la propriété RowFilter est optimale dans une application de liaison de données où un contrôle lié affiche des résultats filtrés. Le paramétrage de la propriété RowFilter entraîne une nouvelle génération de l'index des données, ce qui accroît la charge sur votre application et, par voie de conséquence, fait baisser les performances. Les méthodes Find et FindRows utilisent l'index en cours sans qu'il soit nécessaire de le reconstruire. Si vous ne souhaitez appeler Find ou FindRows qu'une seule fois, il est préférable d'utiliser le DataView existant. Si vous souhaitez appeler Find ou FindRows plusieurs fois, vous devez créer un nouveau DataView pour reconstruire l'index sur la colonne où vous voulez effectuer la recherche, pour appeler la méthode Find ou FindRows. Pour plus d’informations sur les méthodes Find et FindRows, consultez Recherche de lignes et Performances des DataViews.

Suppression du filtre

Le filtre d'un DataView peut être supprimé une fois le filtrage défini à l'aide de la propriété RowFilter. Le filtre sur un DataView peut être supprimé de deux manières différentes :

  • Définissez la propriété RowFilter sur null.

  • Définissez la propriété RowFilter en tant que chaîne vide.

Exemple

L'exemple suivant crée un DataView à partir d'une requête, puis supprime 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