Filtrando com DataView (LINQ to DataSet)
A capacidade de filtrar dados usando critérios específicos e apresentá-los para um cliente através de um controle da interface do usuário é um aspecto importante da vinculação de dados. O DataView fornece várias maneiras para filtrar dados e retornar subconjuntos de linhas de dados que atendem a critérios específicos de filtro. Além dos recursos de filtro baseado em cadeia de caracteres, DataView também tem a capacidade de usar expressões LINQ para os critérios de filtro. As expressões LINQ permitem operações de filtragem muito mais complexas e poderosas do que a filtragem baseada em cadeia de caracteres.
Há duas maneiras para filtrar dados usando um DataView:
Crie um DataView de uma consulta LINQ to DataSet com a cláusula Where.
Use os recursos de filtragem baseados em cadeia de caracteres existentes de DataView.
Criando um DataView a partir de uma consulta com informações de filtragem
Um objeto DataView pode ser criado a partir de uma consulta LINQ to DataSet. Se a consulta contiver uma cláusula Where
, o DataView será criado com as informações de filtragem da consulta. A expressão na cláusula Where
é usada para determinar quais linhas de dados serão incluídas no DataView e é a base para o filtro.
Os filtros baseados em expressão oferecem uma filtragem mais avançada e complexa do que os filtros mais simples baseados em cadeia de caracteres. Os filtros baseados em cadeia de caracteres e baseados em expressão são mutuamente excludentes. Quando a RowFilter baseada em cadeia de caracteres for definida após DataView ser criado a partir de uma consulta, o filtro baseado em expressão inferido da consulta será limpo.
Observação
Na maioria dos casos, as expressões usadas para filtragem não devem ter efeitos colaterais e devem ser determinísticas. Além disso, as expressões não devem conter lógica que dependa de um número definido de execuções, pois as operações de filtragem podem ser executadas qualquer número de vezes.
Exemplo
O exemplo a seguir consulta a tabela SalesOrderDetail para pedidos com uma quantidade maior que 2 e menor que 6; cria DataView a partir da consulta e associa o objeto DataView a uma 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
Exemplo
O exemplo a seguir cria um DataView de uma consulta para os pedidos feitos após 6 de junho de 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
Exemplo
A filtragem também pode ser combinada com a classificação. O exemplo a seguir cria um DataView de uma consulta para os contatos cujo sobrenome comece com "S" e classificados por sobrenome e depois nome:
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()
Exemplo
O exemplo a seguir usa o algoritmo SoundEx para localizar os contatos cujo sobrenome é semelhante a "Zhu". O algoritmo SoundEx é implementado no método 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 é um algoritmo fonético usado para indexar nomes por som, como são pronunciados em inglês, originalmente desenvolvidos pelo Departamento do Censo dos Estados Unidos. O método SoundEx retorna um código de quatro caracteres para um nome que consiste em uma letra em inglês seguida por três números. A letra é a primeira letra do nome e os números codificam as consoantes restantes no nome. Os nomes de som semelhantes compartilham o mesmo código SoundEx. A implementação de SoundEx usada no método SoundEx do exemplo anterior é mostrada aqui:
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
Usando a propriedade RowFilter
A funcionalidade de filtragem existente baseada em cadeia de caracteres de DataView ainda funciona no contexto do LINQ to DataSet. Para obter mais informações sobre filtragem baseada em filtro RowFilter de cadeia de caracteres, consulte Classificação e Filtragem de Dados.
O exemplo a seguir cria um DataView da tabela de contatos e define a propriedade RowFilter para retornar as linhas onde o sobrenome do contatos é "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()
Após um DataView ter sido criado de uma consulta DataTable ou LINQ to DataSet, você pode usar a propriedade RowFilter para especificar subconjuntos de linhas com base nos valores de coluna. Os filtros baseados em cadeia de caracteres e baseados em expressão são mutuamente excludentes. Definir a propriedade RowFilter desmarcará a expressão de filtro inferido da consulta LINQ to DataSet e a expressão de filtro não pode ser redefinida.
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'"
Se você quiser retornar os resultados de uma consulta específica nos dados, ao contrário de fornecer uma exibição dinâmica de um subconjunto dos dados, você poderá usar os métodos Find ou FindRows de DataView, em vez de definir a propriedade RowFilter. A propriedade RowFilter é melhor usada em um aplicativo associado a dados onde um controle de associação exibe resultados filtrados. Definir a propriedade RowFilter reconstrói o índice para os dados, adicionando a sobrecarga ao seu aplicativo e diminuindo o desempenho. Os métodos Find e FindRows usam o índice atual sem exigir que o índice seja reconstruído. Se você chamar Find ou FindRows apenas uma vez, deverá usar o DataView existente. Se você chamar Find ou FindRows várias vezes, deverá criar um novo DataView para recriar o índice na coluna em que você deseja pesquisar e, em seguida, chamar os métodos Find ou FindRows. Para obter mais informações sobre os métodos Find e FindRows, consulte Encontrar linhas e Desempenho do DataView.
Limpando o filtro
O filtro em um objeto DataView podem ser limpas depois da filtragem ter sido definida usando a propriedade RowFilter. O filtro em um DataView pode ser desmarcado de duas maneiras diferentes:
Defina a propriedade RowFilter como
null
.Defina a propriedade RowFilter como uma cadeia de caracteres vazia.
Exemplo
O exemplo a seguir cria um objeto DataView a partir de uma consulta e limpa o filtro definindo a propriedade RowFilter como 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
Exemplo
O exemplo a seguir cria um DataView a partir de uma tabela define a propriedade RowFilter e, em seguida, limpa o filtro configurando a propriedade RowFilter como uma cadeia de caracteres vazia:
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 = ""