Filtern mit 'DataView' (LINQ to DataSet)

Aktualisiert: November 2007

Die Fähigkeit, Daten mittels spezifischer Kriterien zu filtern und sie dann über ein Benutzeroberflächensteuerelement zu präsentieren, ist ein wichtiger Aspekt der Datenbindung. DataView bietet verschiedene Möglichkeiten, Daten zu filtern und Teilmengen von Datenzeilen, die bestimmte Filterkriterien erfüllen, abzurufen. Neben der Filterung auf der Basis von Zeichenfolgen bietet DataView auch die Möglichkeit, LINQ-Ausdrücke als Filterkriterien zu verwenden. LINQ-Ausdrücke ermöglichen wesentlich komplexere und leistungsfähigere Filteroperationen als die zeichenfolgenbasierte Filterung.

Es gibt zwei Möglichkeiten, Daten mit einer DataView zu filtern:

  • durch Erstellen einer DataView mittels einer WHERE-Klausel aus einer LINQ to DataSet-Abfrage

  • mittels der vorhandenen Funktionen für das zeichenfolgenbasierte Filtern von DataView

Erstellen einer "DataView" auf der Grundlage einer Abfrage mit Filterinformationen

Ein DataView-Objekt kann auf der Grundlage einer LINQ to DataSet-Abfrage erstellt werden. Wenn die Abfrage eine Where-Klausel enthält, wird die DataView mit den Filterinformationen aus der Abfrage erstellt. Der Ausdruck in der Where-Klausel wird verwendet, um zu bestimmen, welche Datenzeilen in die DataView aufgenommen werden. Er bildet gleichzeitig die Basis für den Filter.

Ausdrucksbasierte Filter bieten leistungsfähigere und komplexere Filterfunktionen als die einfacheren zeichenfolgenbasierten Filter. Die zeichenfolgenbasierten und ausdrucksbasierten Filter schließen sich gegenseitig aus. Wenn der zeichenfolgenbasierte RowFilter festgelegt wird, nachdem eine DataView auf der Grundlage einer Abfrage erstellt wurde, wird der ausdrucksbasierte Filter, der aus der Abfrage abgeleitet wurde, gelöscht.

Hinweis:

In den meisten Fällen dürften die für die Filterung verwendeten Ausdrücke keine Nebenwirkungen haben. Sie müssen deterministisch sein. Die Ausdrücke dürfen darüber hinaus keine Logik enthalten, die auf einer festgelegten Anzahl von Ausführungen beruht, da die Filteroperationen unbegrenzt oft ausgeführt werden können sollen.

Beispiel

Im folgenden Beispiel werden aus der SalesOrderDetail-Tabelle alle Aufträge mit einer Menge größer als 2 und kleiner als 6 abgerufen. Dann wird aus dieser Abfrage eine DataView erstellt. Die DataView wird anschließend an eine BindingSource gebunden:

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;

Beispiel

Im folgenden Beispiel wird eine DataView auf der Grundlage einer Abfrage erstellt, die alle nach dem 6. Juni 2001 eingegangenen Aufträge abruft:

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;

Beispiel

Die Filterung kann auch mit der Sortierung kombiniert werden. Im folgenden Beispiel wird eine DataView auf der Grundlage einer Abfrage nach Kontaktpersonen erstellt, deren Nachname mit S beginnt. Die Ergebnisse werden erst nach dem Nachnamen und dann nach dem Vornamen sortiert:

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();

Beispiel

Im folgenden Beispiel wird der SoundEx-Algorithmus verwendet, um Kontakte zu suchen, deren Nachname "Zhu" ähnlich ist. Der SoundEx-Algorithmus ist in der SoundEx-Methode implementiert.

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 ist ein ursprünglich durch das U.S. Census Bureau entwickelter phonetischer Algorithmus, mit dem Namen nach ihrem Klang im Englischen indiziert werden können. Die SoundEx-Methode gibt für den Namen einen vierstelligen Code zurück, der aus einem Buchstaben und drei Zahlen besteht. Der Buchstabe ist der erste Buchstabe des Namens, und die Zahlen sind die verschlüsselten restlichen Konsonanten im Namen. Ähnlich klingende Namen haben denselben SoundEx-Code. Die in der SoundEx-Methode im vorherigen Beispiel verwendete SoundEx-Implementierung sieht wie folgt aus:

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;            
}

Verwenden der "RowFilter"-Eigenschaft

Die bisherige zeichenfolgenbasierte Filterfunktionalität von DataView funktioniert auch im LINQ to DataSet-Kontext noch. Weitere Informationen zur zeichenfolgenbasierten RowFilter-Filterung finden Sie unter Sortieren und Filtern von Daten (ADO.NET).

Im folgenden Beispiel wird eine DataView auf der Grundlage der Contact-Tabelle erstellt und dann die RowFilter-Eigenschaft so eingerichtet, dass alle Zeilen zurückgegeben werden, bei denen der Nachname des Kontakts "Zhu" lautet:

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();

Nachdem eine DataView aus einer DataTable oder LINQ to DataSet-Abfrage erstellt wurde, können Sie die RowFilter-Eigenschaft verwenden, um auf der Grundlage der jeweiligen Spaltenwerte Teilmengen von Zeilen anzugeben. Die zeichenfolgenbasierten und ausdrucksbasierten Filter schließen sich gegenseitig aus. Durch die Einrichtung der RowFilter-Eigenschaft wird der aus der LINQ to DataSet-Abfrage abgeleitete Filterausdruck gelöscht. Er kann dann nicht wiederhergestellt werden.

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'";

Wenn Sie die Ergebnisse einer bestimmten Abfrage von Daten zurückgeben möchten, anstatt eine dynamische Ansicht einer Teilmenge von Daten zu erhalten, können Sie die Methode Find oder FindRows der DataView verwenden, statt die RowFilter-Eigenschaft einzurichten. Die RowFilter-Eigenschaft wird am besten in einer datengebundenen Anwendung verwendet, in der ein gebundenes Steuerelement gefilterte Ergebnisse anzeigt. Wenn Sie die RowFilter-Eigenschaft festlegen, wird der Index für die Daten neu erstellt, wodurch zusätzlicher Verwaltungsaufwand für die Anwendung entsteht und die Arbeitsgeschwindigkeit verringert wird. Die Methoden Find und FindRows nutzen den aktuellen Index, ohne dass der Index neu erstellt werden muss. Wenn Sie Find oder FindRows nur einmal aufrufen werden, sollten Sie die vorhandene DataView verwenden. Wird Find oder FindRows dagegen mehrmals aufgerufen, empfiehlt sich die Erstellung einer neuen DataView, um den Index auf der Basis der zu durchsuchenden Spalte neu zu erstellen, bevor die Methode Find oder FindRows aufgerufen wird. Weitere Informationen über die Methoden Find und FindRows finden Sie unter Suchen nach Zeilen (ADO.NET) und 'DataView'-Arbeitsgeschwindigkeit.

Löschen des Filters

Der Filter für eine DataView kann gelöscht werden, nachdem die Filterung mit der RowFilter-Eigenschaft eingerichtet wurde. Das Löschen des Filters für eine DataView kann auf zweierlei Art und Weise erfolgen:

  • indem die RowFilter-Eigenschaft auf null gesetzt wird

  • indem für die RowFilter-Eigenschaft eine leere Zeichenfolge festgelegt wird

Beispiel

Im folgenden Beispiel wird eine DataView auf der Grundlage einer Abfrage erstellt und dann der Filter gelöscht, indem die RowFilter-Eigenschaft auf null gesetzt wird:

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;

Beispiel

Im folgenden Beispiel wird eine DataView auf der Grundlage einer Tabelle erstellt und die RowFilter-Eigenschaft festgelegt. Anschließend wird der Filter gelöscht, indem für die RowFilter-Eigenschaft eine leere Zeichenfolge festgelegt wird:

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 = "";

Siehe auch

Konzepte

Datenbindung und LINQ to DataSet

Sortieren mit 'DataView' (LINQ to DataSet)