Filteren met DataView (LINQ naar DataSet)
De mogelijkheid om gegevens te filteren op basis van specifieke criteria en de gegevens vervolgens aan een client te presenteren via een UI-besturingselement, is een belangrijk aspect van gegevensbinding. DataView biedt verschillende manieren om gegevens te filteren en subsets van gegevensrijen te retourneren die voldoen aan specifieke filtercriteria. Naast de filtermogelijkheden op basis van tekenreeksen biedt DataView u ook de mogelijkheid om LINQ-expressies te gebruiken voor de filtercriteria. LINQ-expressies bieden veel complexere en krachtige filterbewerkingen dan het filteren op basis van tekenreeksen.
Er zijn twee manieren om gegevens te filteren met behulp van een DataView:
Maak een DataView van een LINQ naar DataSet-query met een Where-component.
Gebruik de bestaande filtermogelijkheden op basis van tekenreeksen van DataView.
DataView maken op basis van een query met filterinformatie
Een DataView object kan worden gemaakt van een LINQ naar DataSet-query. Als die query een Where
component bevat, wordt deze DataView gemaakt met de filterinformatie uit de query. De expressie in de Where
component wordt gebruikt om te bepalen welke gegevensrijen worden opgenomen in de DataViewen is de basis voor het filter.
Op expressies gebaseerde filters bieden krachtigere en complexere filters dan de eenvoudigere filters op basis van tekenreeksen. De filters op basis van tekenreeksen en expressies sluiten elkaar wederzijds uit. Wanneer de tekenreeks RowFilter is ingesteld nadat een DataView query is gemaakt, wordt het filter op basis van expressies uit de query gewist.
Notitie
In de meeste gevallen mogen de expressies die worden gebruikt voor filteren geen bijwerkingen hebben en moeten ze deterministisch zijn. De expressies mogen ook geen logica bevatten die afhankelijk is van een vast aantal uitvoeringen, omdat de filterbewerkingen mogelijk een willekeurig aantal keren worden uitgevoerd.
Opmerking
In het volgende voorbeeld wordt een query uitgevoerd op de tabel SalesOrderDetail voor orders met een hoeveelheid groter dan 2 en minder dan 6; maakt een DataView van die query en verbindt de DataView aan een 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
Opmerking
In het volgende voorbeeld wordt een DataView query gemaakt voor orders die na 6 juni 2001 zijn geplaatst:
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
Opmerking
Filteren kan ook worden gecombineerd met sorteren. In het volgende voorbeeld wordt een DataView query gemaakt voor contactpersonen waarvan de achternaam begint met 'S' en gesorteerd op achternaam en vervolgens op voornaam:
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()
Opmerking
In het volgende voorbeeld wordt het SoundEx-algoritme gebruikt om contactpersonen te zoeken waarvan de achternaam vergelijkbaar is met 'Zhu'. Het SoundEx-algoritme wordt geïmplementeerd in de SoundEx-methode.
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 is een fonetisch algoritme dat wordt gebruikt voor het indexeren van namen door geluid, zoals ze worden uitgesproken in het Engels, oorspronkelijk ontwikkeld door het Amerikaanse Census Bureau. De SoundEx-methode retourneert een code van vier tekens voor een naam die bestaat uit een Engelse letter, gevolgd door drie cijfers. De letter is de eerste letter van de naam en de cijfers coderen de resterende medeklinkers in de naam. Vergelijkbare klinkende namen delen dezelfde SoundEx-code. De SoundEx-implementatie die in de SoundEx-methode van het vorige voorbeeld wordt gebruikt, wordt hier weergegeven:
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
De eigenschap RowFilter gebruiken
De bestaande filterfunctionaliteit op basis van tekenreeksen werkt DataView nog steeds in de LINQ naar de DataSet-context. Zie Gegevens sorteren en filteren voor meer informatie over filteren op basis van RowFilter tekenreeksen.
In het volgende voorbeeld wordt een DataView uit de tabel Contactpersoon gemaakt en wordt de RowFilter eigenschap ingesteld om rijen te retourneren waarbij de achternaam van de contactpersoon 'Zhu' is:
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()
Nadat een DataView query is gemaakt op basis van een DataTable of LINQ naar DataSet-query, kunt u de RowFilter eigenschap gebruiken om subsets van rijen op te geven op basis van hun kolomwaarden. De filters op basis van tekenreeksen en expressies sluiten elkaar wederzijds uit. Als u de RowFilter eigenschap instelt, wordt de filterexpressie gewist die is afgeleid van de LINQ naar de DataSet-query en kan de filterexpressie niet opnieuw worden ingesteld.
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'"
Als u de resultaten van een bepaalde query op de gegevens wilt retourneren, in plaats van een dynamische weergave van een subset van de gegevens te bieden, kunt u de Find of FindRows methoden van de DataVieweigenschap gebruiken in plaats van de RowFilter eigenschap in te stellen. De RowFilter eigenschap wordt het beste gebruikt in een gegevensgebonden toepassing waarbij een afhankelijk besturingselement gefilterde resultaten weergeeft. Als u de RowFilter eigenschap instelt, wordt de index voor de gegevens opnieuw opgebouwd, waardoor overhead aan uw toepassing wordt toegevoegd en de prestaties afnemen. De Find en FindRows methoden gebruiken de huidige index zonder dat de index opnieuw moet worden opgebouwd. Als u belt Find of FindRows slechts één keer, moet u de bestaande DataViewgebruiken. Als u wilt bellen Find of FindRows meerdere keren, moet u een nieuwe DataView maken om de index opnieuw op te bouwen op de kolom waarop u wilt zoeken en vervolgens de Find of FindRows methoden aanroepen. Zie Rijen en DataView-prestaties zoeken voor meer informatie over de Find en FindRows methoden.
Het filter wissen
Het filter op een DataView kan worden gewist nadat het filteren is ingesteld met behulp van de RowFilter eigenschap. Het filter op een DataView kan op twee verschillende manieren worden gewist:
Opmerking
In het volgende voorbeeld wordt een DataView query gemaakt en wordt vervolgens het filter gewist door de eigenschap in te stellen RowFilter op 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
Opmerking
In het volgende voorbeeld wordt een DataView van een tabel gemaakt en wordt de RowFilter eigenschap ingesteld en wordt het filter gewist door de RowFilter eigenschap in te stellen op een lege tekenreeks:
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 = ""