Compartir a través de


Filtrar con DataView (LINQ to DataSet)

La capacidad de filtrar datos utilizando criterios específicos y después presentarlos a un cliente mediante un control de IU es un aspecto importante del enlace de datos. DataView proporciona varias maneras de filtrar datos y devolver subconjuntos de filas de datos que reúnan determinados criterios. Además de capacidades de filtro basado en cadena, DataView también proporciona la capacidad de utilizar expresiones LINQ para los criterios de filtro. Las expresiones LINQ permiten operaciones de filtro más complejas y eficaces que el filtro basado en cadena.

Existen dos maneras de filtrar datos utilizando DataView:

  • Crear un DataView a partir de una consulta LINQ to DataSet con una cláusula WHERE.

  • Utilizar las capacidades de filtro basado en cadena de DataView existentes.

Crear DataView desde una consulta con información de filtro

Se puede crear un objeto DataView desde una consulta LINQ to DataSet. Si dicha consulta tiene una cláusula Where, DataView se crea con información de filtro desde la consulta. La expresión de la cláusula Where se utiliza para determinar qué filas de datos se incluirán en DataView, y constituye la base para el filtro.

Los filtros basados en expresión son más eficaces y complejos que los sencillos filtros basados en cadena. Los filtros basados en cadena y los basados en expresión se excluyen mutuamente. Cuando el RowFilter basado en cadena se establece después de haber creado DataView desde una consulta, se borra el filtro basado en expresión inferido a partir de la consulta.

NotaNota

En la mayor parte de los casos, las expresiones utilizadas en el filtro no deben tener efectos secundarios y deben ser deterministas.Además, las expresiones no deben tener ninguna lógica que dependa de un número de conjunto de ejecuciones, porque las operaciones de filtrado se pueden ejecutar un número ilimitado de veces.

Ejemplo

El siguiente ejemplo consulta en la tabla SalesOrderDetail los pedidos con una cantidad superior a 2 e inferior a 6; crea un DataView desde una consulta y enlaza DataView a un BindingSource:

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;

Ejemplo

El siguiente ejemplo crea un DataView desde una consulta de pedidos efectuados con posterioridad al 6 de junio de 2001:

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;

Ejemplo

El filtro se puede combinar también con la ordenación. El siguiente ejemplo crea un DataView desde una consulta de contactos cuyos apellidos empiezan por la letra "S", y los ordena primero por el apellido y después por el nombre:

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

Ejemplo

El siguiente ejemplo utiliza el algoritmo SoundEx para encontrar contactos cuyo apellido es similar a "Zhu". El algoritmo SoundEx se implementa en el método SoundEx.

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 es un algoritmo fonético utilizado para indizar nombres según el sonido, tal como se pronuncian en inglés, que fue desarrollado originalmente por la Oficina del Censo de Estados Unidos. El método SoundEx devuelve un código de cuatro caracteres para un nombre que consiste en una letra inglesa seguida de tres números. La letra es la primera letra del nombre y los números codifican el resto de las consonantes del mismo. Los nombres que suenan parecidos comparten el mismo código SoundEx. A continuación se muestra la implementación del SoundEx utilizado en el método SoundEx del ejemplo anterior:

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

Utilizar la propiedad RowFilter

La funcionalidad de filtro basado en cadena DataView existente funciona también en el contexto de LINQ to DataSet. Para obtener más información sobre filtro RowFilter basado en cadena, vea Ordenar y filtrar datos (ADO.NET).

El siguiente ejemplo crea un DataView desde la tabla Contact y, a continuación, establece la propiedad RowFilter para que devuelva filas cuando el apellido del contacto sea "Zhu":

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

Después de haberse creado un DataView desde una consulta DataTable o LINQ to DataSet, se puede utilizar la propiedad RowFilter para especificar subconjuntos de filas basados en sus valores de columna. Los filtros basados en cadena y los basados en expresión se excluyen mutuamente. Al establecer la propiedad RowFilter se borrará la expresión de filtro inferida a partir de la consulta LINQ to DataSet, y la expresión de filtro no se podrá volver a restablecer.

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

Si desea devolver los resultados de una consulta determinada en los datos, en lugar de proporcionar una vista dinámica de un subconjunto de los datos, para conseguir el máximo rendimiento puede utilizar los métodos Find o FindRows de la DataView, en lugar de establecer la propiedad RowFilter. La propiedad RowFilter es más idónea en una aplicación enlazada a datos donde un control enlazado muestra resultados filtrados. El establecimiento de la propiedad RowFilter hace que se vuelva a compilar el índice de los datos, lo que agrega sobrecarga a la aplicación y reduce el rendimiento. Los métodos Find y FindRows utilizan el índice actual, sin necesidad de volver a compilarlo. Si va a llamar a Find o a FindRows una única vez, entonces debería utilizar el DataView existente. Si va a llamar a Find o a FindRows varias veces, debería crear un nuevo DataView para volver a compilar el índice en la columna en la que desea buscar y, a continuación, llamar a los métodos Find o FindRows. Para obtener más información acerca de los métodos Find y FindRows vea Buscar filas (ADO.NET) y Rendimiento DataView.

Borrar el filtro

Después de haber configurado el filtro de DataView, éste se puede borrar mediante la propiedad RowFilter. El filtro de DataView se pude borrar de dos maneras:

  • Establecer la propiedad RowFilter en null.

  • Establecer la propiedad RowFilter en una cadena vacía.

Ejemplo

El siguiente ejemplo crea un DataView desde una consulta y, a continuación, borra el filtro estableciendo la propiedad RowFilter en 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
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;

Ejemplo

El siguiente ejemplo crea un DataView desde una tabla, establece la propiedad RowFilter y, a continuación, borra el filtro estableciendo la propiedad RowFilter en una cadena vacía:

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

Vea también

Conceptos

Enlace de datos y LINQ to DataSet

Ordenar con DataView (LINQ to DataSet)