Поделиться через


Фильтрация с помощью DataView (LINQ to DataSet)

Возможность фильтровать данные с помощью определенных критериев, а затем представлять данные клиенту с помощью элемента управления пользовательским интерфейсом является важным аспектом привязки данных. DataView предоставляет несколько способов фильтрации данных и возвращать подмножества строк данных с определенными критериями фильтра. Помимо возможностей фильтрации на основе строк, DataView также предоставляет возможность использовать выражения LINQ для критериев фильтрации. Выражения LINQ позволяют выполнять гораздо более сложные и мощные операции фильтрации, чем фильтрация на основе строк.

Существует два способа фильтрации данных с помощью DataView:

  • Создайте DataView из запроса LINQ to DataSet с предложением Where.

  • Используйте существующие возможности DataViewфильтрации на основе строк.

Создание DataView из запроса с помощью сведений о фильтрации

Объект DataView можно создать из запроса LINQ to DataSet. Если этот запрос содержит Where условие, DataView создается на основе сведений о фильтрации из запроса. Выражение в Where условии используется для определения строк данных, которые будут включены в DataView, и является основой для фильтра.

Фильтры на основе выражений предлагают более мощные и сложные фильтры, чем более простые строковые фильтры. Фильтры на основе строк и выражений являются взаимоисключающими. Когда строковый RowFilter устанавливается после того, как DataView создан из запроса, фильтр на основе выражений, выведенный из запроса, очищается.

Замечание

В большинстве случаев выражения, используемые для фильтрации, не должны иметь побочных эффектов и должны быть детерминированными. Кроме того, выражения не должны содержать логику, которая зависит от заданного количества выполнений, так как операции фильтрации могут выполняться любое количество раз.

Пример

В следующем примере запрашивается таблица SalesOrderDetail для заказов с количеством, превышающим 2 и менее 6; создается DataView из этого запроса и DataView привязывается к 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

Пример

В следующем примере из запроса на заказы, размещенные после 6 июня 2001 года, создается DataView.

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

Пример

Фильтрация также может сочетаться с сортировкой. В следующем примере создается DataView на основе запроса для контактов, чьи фамилии начинаются с "S" и которые отсортированы сначала по фамилии, а затем по имени.

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

Пример

В следующем примере используется алгоритм SoundEx для поиска контактов, фамилия которых похожа на "Чжу". Алгоритм SoundEx реализуется в методе 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 — это фонетический алгоритм, используемый для индексирования имен по звуку, так как они произносится на английском языке, первоначально разработанный Бюро переписи населения США. Метод SoundEx возвращает четыре символьного кода для имени, состоящего из английского буквы, за которым следует три числа. Буква — это первая буква имени, а цифры кодируют оставшиеся консонанты в имени. Аналогичные имена звуков используют тот же код SoundEx. Реализация SoundEx, используемая в методе SoundEx предыдущего примера, показана здесь:

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

Использование свойства RowFilter

Существующие функции DataView фильтрации на основе строк по-прежнему работают в контексте LINQ to DataSet. Дополнительные сведения о фильтрации на основе RowFilter строк см. в разделе "Сортировка и фильтрация данных".

В следующем примере создается DataView из таблицы Contact, а затем задается свойство RowFilter, чтобы возвращать строки, в которых фамилия контакта — «Чжу».

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

После создания DataView из запроса DataTable или LINQ to DataSet, можно использовать свойство RowFilter, чтобы указать подмножества строк, основанные на значениях столбцов. Фильтры на основе строк и выражений являются взаимоисключающими. Установка свойства RowFilter очистит выражение фильтра, построенное на основе запроса LINQ to DataSet, и выражение фильтра не может быть восстановлено.

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

Если вы хотите вернуть результаты определенного запроса к данным, а не предоставлять динамическое представление подмножества данных, можно использовать методы Find или FindRows из DataView, а не задавать свойство RowFilter. Свойство RowFilter лучше всего используется в приложении с привязкой к данным, где привязанный элемент управления отображает отфильтрованные результаты. RowFilter Задание свойства перестраивает индекс для данных, создавая дополнительную нагрузку на ваше приложение и уменьшая производительность. Методы Find и FindRows используют текущий индекс без необходимости перестраивать индекс. Если вы собираетесь вызвать Find или FindRows только один раз, следует использовать существующий DataView. Если вы собираетесь вызывать Find или FindRows несколько раз, необходимо создать новый DataView для перестроения индекса в столбце, по которому требуется выполнить поиск, а затем вызвать методы Find или FindRows. Дополнительные сведения о FindFindRowsметодах поиска строк и производительности DataView см. в разделе "Поиск строк" и " Производительность DataView".

Очистка фильтра

Фильтр в DataView можно очистить после применения фильтрации с помощью свойства RowFilter. Фильтр на объекте DataView можно очистить двумя разными способами:

  • Задайте для свойства RowFilter значение null.

  • RowFilter Задайте для свойства пустую строку.

Пример

В следующем примере из запроса создается DataView, а затем фильтр очищается путем установки свойства RowFilter в значение 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

Пример

В следующем примере создается DataView, исходя из таблицы, задается свойство RowFilter, а затем фильтр очищается, присваивая свойству 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 = "";
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 = ""

См. также