Фильтрация с использованием объекта 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.
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
Пример
В следующем примере объект DataView создается на основе заказов, размещенных позже 6 июня 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
Пример
Фильтрация может быть совмещена с сортировкой. В следующем примере объект 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 используется для поиска контактов с фамилией, сходной с «Zhu». Алгоритм 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 для возврата строк, содержащих контакты с фамилией «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()
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. Дополнительные сведения о Find FindRows методах поиска строк и производительности DataView см. в разделе "Поиск строк" и "Производительность DataView".
Очистка фильтра
Фильтр для объекта DataView можно очистить после его задания с помощью свойства RowFilter. Фильтр для объекта DataView можно очистить двумя различными способами.
Пример
В следующем примере объект 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 = ""