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 chaîne, 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 bien plus complexes et puissantes que le filtrage basé sur chaîne.
Il existe deux façons de filtrer des données à l'aide d'un DataView :
Créer un DataView à partir d'une requête LINQ to DataSet comprenant 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é.
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.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 :
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
DataTable orders = dataSet.Tables["SalesOrderDetail"];
EnumerableRowCollection<DataRow> query = from order in orders.AsEnumerable()
where order.Field<Int16>("OrderQty") > 2 && order.Field<Int16>("OrderQty") < 6
select order;
DataView view = 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 :
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
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;
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 :
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()
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();
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.
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()
DataTable contacts = dataSet.Tables["Contact"];
string 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();
SoundEx est un algorithme phonétique qui sert à indexer les noms par son, tels qu'ils sont prononcés en anglais, qui a été développé à l'origine par le Bureau de 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 :
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
static private string SoundEx(string word)
{
// The length of the returned code.
int length = 4;
// Value to return.
string value = "";
// The size of the word to process.
int 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(System.Globalization.CultureInfo.InvariantCulture);
// Convert the word to a character array.
char[] chars = word.ToCharArray();
// Buffer to hold the character codes.
StringBuilder buffer = new StringBuilder();
buffer.Length = 0;
// The current and previous character codes.
int prevCode = 0;
int 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 (int 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;
}
Utilisation de la propriété RowFilter
La fonctionnalité de filtrage basé sur chaîne existante de DataView fonctionne toujours dans le contexte de LINQ to DataSet. Pour plus d'informations sur le filtrage RowFilter basé sur chaîne, voir Tri et filtrage de données (ADO.NET).
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 » :
Dim contacts As DataTable = dataSet.Tables("Contact")
Dim view As DataView = contacts.AsDataView()
view.RowFilter = "LastName='Zhu'"
bindingSource1.DataSource = view
dataGridView1.AutoResizeColumns()
DataTable contacts = dataSet.Tables["Contact"];
DataView view = contacts.AsDataView();
view.RowFilter = "LastName='Zhu'";
bindingSource1.DataSource = view;
dataGridView1.AutoResizeColumns();
Une fois qu'un DataView a été créé à partir d'une requête DataTable or LINQ to DataSet, vous pouvez utiliser la propriété RowFilter pour spécifier des sous-ensembles de lignes basés sur leurs valeurs de colonne. Les filtres basés sur chaîne et sur une expression s'excluent mutuellement. La définition de la propriété RowFilter 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.
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'"
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'";
Si vous souhaitez retourner les résultats d'une requête particulière exécutée sur les données, au lieu de fournir une vue dynamique d'un sous-ensemble des données, vous pouvez 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, voir Recherche de lignes (ADO.NET) et Performances des DataView.
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 :
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
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;
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 :
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 = ""
DataTable contacts = dataSet.Tables["Contact"];
DataView view = contacts.AsDataView();
view.RowFilter = "LastName='Zhu'";
bindingSource1.DataSource = view;
dataGridView1.AutoResizeColumns();
// Clear the row filter.
view.RowFilter = "";