Filtrar las columnas de una tabla y realizar búsquedas en un DataSet
[Mejorando el rendimiento de la aplicación y ralizando búsquedas rápidas trabajando en modo desconectado]

Fecha: 23/Ene/2005 (20/01/2005)
Autor: Percy Reyes - Perxindrome ([email protected]

 


Una de las características de esta nueva tecnología .NET es que los desarrolladores podemos construir aplicaciones cada vez más escalables, esto es debido a que podemos trabajar en modo desconectado; es decir, reduciendo al máximo el número de "conexiones abiertas" en la base de datos. Además sabemos que anteriormente se obtenía mejor rendimiento manteniendo una conexión abierta para la conexión a la fuente de datos, esto era utilizando ADO, pero como todo cambia conforme avanza la tecnología y la ciencia, es así que gracias a los famosos DataSets nos damos ese privilegio de tomar una parte de los datos y trabajar con ellos manteniéndolos en memoria en forma relacional. Todo esto se lo debemos a Microsoft por haber considerado en su gran lista de prioridades para ADO .NET lo antes mencionado. Para entender todos estos conceptos, creo conveniente que debe quedar claro algunas cosillas con respecto a ADO .NET.

ADO .NET Constituye la interfaz fundamental de las aplicaciones para proporcionar servicios de acceso a datos en la plataforma Microsoft .NET. ADO.NET proporciona acceso coherente a orígenes de datos como Microsoft SQL Server, así como a orígenes de datos expuestos mediante OLE DB y XML. Las aplicaciones para usuarios que comparten datos pueden utilizar ADO.NET para conectar a estos orígenes de datos y recuperar, manipular y actualizar los datos.

ADO.NET separa limpiamente el acceso a datos de la manipulación de datos y crea componentes discretos que se pueden usar por separado o conjuntamente. ADO.NET incluye proveedores de datos de .NET Framework para conectarse a una base de datos, ejecutar comandos y recuperar resultados. Esos resultados se procesan directamente o se colocan en un objeto DataSet de ADO.NET con el fin de exponerlos al usuario para un propósito específico, junto con datos de varios orígenes, o de utilizarlos de forma remota entre niveles. El objeto DataSet de ADO.NET también puede utilizarse independientemente de un proveedor de datos de .NET Framework para administrar datos que son locales de la aplicación o que proceden de un origen XML.

Las clases de ADO.NET se encuentran en System.Data.dll y se integran con las clases de XML incluidas en System.Xml.dll. Al compilar código que utiliza el espacio de nombres System.Data, haga referencia tanto a System.Data.dll como a System.Xml.dll. ADO.NET proporciona a los programadores que escriben código administrado una funcionalidad parecida a la que ADO proporciona a los programadores de COM nativo. Para obtener una descripción de las diferencias entre ADO y ADO.NET, te invito a ver "ADO.NET para el programador de ADO" en http://msdn.microsoft.com/library/en-us/dndotnet/html/ADONETProg.asp.

El DataSet de ADO.NET es una representación de datos residente en memoria que proporciona un modelo de programación relacional coherente independientemente del origen de datos que contiene. Un DataSet representa un conjunto completo de datos, incluyendo las tablas que contienen, ordenan y restringen los datos, así como las relaciones entre las tablas.

El objetivo de este artículo no es explicar a fondo todo respecto a ADO .NET, sino más bien poner en práctica algunos conceptos arriba explicados. A continuación vamos directo al grano; es decir al ejemplo. Trataré de no ser tan bruto para explicarles lo que implementé en mi preferido lenguaje Visual Basic .NET. Mostraré un ejemplo donde se trabajará con todas la tablas de la base de datos Northwind, donde después de "vaciar" las tablas de la base de datos en una dataset procederemos a visualizar en una grilla tan sólo las columnas que el usuario seleccione. Luego haremos la consulta en la tabla Customers de todos los clientes de acuerdo al país, para nuestro ejemplo será "France".Los resultados se visualizarán en otra grilla.


En la parte baja de este artículo se encuentra el fichero con el código de la aplicación que implementé, donde podrás chekear mejor el programa. A continuación sigue el código en Visual Basic .Net:

'La cadena de conexión se declara en un módulo.
Module Module1
    Public StringConexion As String = "Data Source=(Local);Initial Catalog=Northwind; Integrated Security=SSPI"
End Module


Imports System.Data.SqlClient
Public Class Form1
    Inherits System.Windows.Forms.Form
    Public Shared MiDataset As New DataSet
    Public i As Integer = 0


    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        BtnFiltrarColumnas.Enabled = False
        GroupBox1.Enabled = False
        'Establecemos las cadenas de comandos y conexiones para 
        'acceder a cada una de las tablas de la base de datos
        Dim Adaptador1 As New SqlDataAdapter("SELECT * FROM Products", StringConexion)
        Dim Adaptador2 As New SqlDataAdapter("SELECT * FROM customercustomerdemo", StringConexion)
        Dim Adaptador3 As New SqlDataAdapter("SELECT * FROM customerdemographics", StringConexion)
        Dim Adaptador4 As New SqlDataAdapter("SELECT * FROM employeeterritories", StringConexion)
        Dim Adaptador5 As New SqlDataAdapter("SELECT * FROM territories", StringConexion)
        Dim Adaptador6 As New SqlDataAdapter("SELECT * FROM suppliers", StringConexion)
        Dim Adaptador7 As New SqlDataAdapter("SELECT * FROM employees", StringConexion)
        Dim Adaptador8 As New SqlDataAdapter("SELECT * FROM shippers", StringConexion)
        Dim Adaptador9 As New SqlDataAdapter("SELECT * FROM region", StringConexion)
        Dim Adaptador10 As New SqlDataAdapter("SELECT * FROM Customers", StringConexion)
        Dim Adaptador11 As New SqlDataAdapter("SELECT * FROM orders", StringConexion)
        Dim Adaptador12 As New SqlDataAdapter("SELECT * FROM [Order Details]", StringConexion)
        Dim Adaptador13 As New SqlDataAdapter("SELECT * FROM Categories", StringConexion)
        'Ahora instanciamos una DataSet.
        MiDataset = New DataSet
        'enlazando al dataset con el adapter correspondiente.
        Adaptador1.Fill(miDataset, "Products")
        Adaptador2.Fill(MiDataset, "customercustomerdemo")
        Adaptador3.Fill(miDataset, "customerdemographics")
        Adaptador4.Fill(miDataset, "[employeeterritories]")
        Adaptador5.Fill(miDataset, "territories")
        Adaptador6.Fill(miDataset, "suppliers")
        Adaptador7.Fill(miDataset, "employees")
        Adaptador8.Fill(miDataset, "shippers")
        Adaptador9.Fill(miDataset, "region")
        Adaptador10.Fill(miDataset, "Customers")
        Adaptador11.Fill(miDataset, "orders")
        Adaptador12.Fill(miDataset, "[Order Details]")
        Adaptador13.Fill(miDataset, "Categories")
        For i = 0 To miDataset.Tables.Count - 1
            CboLista.Items.Add(MiDataset.Tables(i).TableName)
        Next
        'Seleccionamos por defecto la tabla [employeeterritories]. 
        CboLista.SelectedIndex = 0
        'Ahora establecemos el texto correspondiente al título 
        'de la ventana de nuestro DataGrid1 como "[employeeterritories]".
        DataGrid1.CaptionText = CboLista.Text
        For i = 0 To (Me.miDataset.Tables(CboLista.Text).Columns.Count - 1)
            'Procedemos a llenar nuestro ListBox1 con los nombres de la 
            'tabla [employeeterritories], los cuales serán usados para 
            'elegir en que tabla realizaremos la respectivas búsquedas.
            Me.ListBox1.Items.Add(Me.miDataset.Tables(CboLista.Text).Columns.Item(i).Caption)
        Next
        MostrarColumnas(CboLista.Text)
    End Sub
    'Esta función servirá para mostrar todas las columnas del DataSet 
    'que fueron checkeadas en LstColumnas.
    Private Function FiltrarDataSet() As DataSet
        Try
            Dim TemporalDataSet As New DataSet
            Dim Columna As DataColumn
            TemporalDataSet = Me.MiDataset.Copy()
            'Filtraremos  todos los Chek que no están selecionados, 
            'para después eliminarmos.
            For i = 0 To Me.Lstcolumnas.Items.Count - 1
                If Not Me.Lstcolumnas.GetItemChecked(i) Then
                    ' Recuperamos el nombre para determinar la columna a eliminar.
                    Columna = TemporalDataSet.Tables(CboLista.Text).Columns(Me.Lstcolumnas. _
                    GetItemText(Me.Lstcolumnas.Items.Item(i)))
                        'Ahora borramos la columna.
                        TemporalDataSet.Tables(CboLista.Text).Columns.Remove(Columna)
                    End If
                Next
                CboLista.Enabled = True
                Return TemporalDataSet
            Catch ex As Exception
                MsgBox(ex.Message)
            End Try
        End Function

        Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) _
            Handles Timer1.Tick
            Label1.Visible = False
            Timer2.Enabled = True
            Timer1.Enabled = False
        End Sub
        Private Sub Timer2_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) _
            Handles Timer2.Tick
            Label1.Visible = True
            Timer1.Enabled = True
            Timer2.Enabled = False
        End Sub
        Private Sub LinkLabel1_LinkClicked(ByVal sender As System.Object, ByVal e As _
            System.Windows.Forms.LinkLabelLinkClickedEventArgs) Handles LinkLabel1.LinkClicked
            Dim NewProcess As New Process
            'Este es el código Html que nos permite llamar al Outlook Express.
            NewProcess.Start("mailto:[email protected]?subject=(ninguno)")
        End Sub

        Private Sub BtnSalir_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
            Handles BtnSalir.Click
            Dim respuesta As DialogResult
            respuesta = MsgBox(" ¿Seguro que desea salir?", MsgBoxStyle.DefaultButton3 + _
            MsgBoxStyle.YesNo + MsgBoxStyle.Question, "Cerrar Aplicación")
            If respuesta = DialogResult.Yes Then
                Me.Close()
            End If
        End Sub

        Private Sub BtnTodos_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
            Handles BtnTodos.Click
            'Recordemos que la DataGrid para llenar los resultados es Datagrid2.
            Me.DataGrid2.DataSource = Me.MiDataset.Tables(CboLista.Text)
            Dim j As Integer = 0
            Try
                'Búscamos en cada fila de acuerdo a la columna especificada en el Listbox1.
                For i = 0 To (Me.MiDataset.Tables(CboLista.Text).Rows.Count - 1)
                    If Not (Me.TxtConsulta.Text.Equals(Me.MiDataset.Tables(CboLista.Text).Rows. _
                    Item(i).Item(ListBox1.SelectedIndex))) Then
                    'Los registros no encontrados serán eliminados. De esta manera se irá 
                    'filtrando los registros encontrados.
                    Me.MiDataset.Tables(CboLista.Text).Rows.Item(i).Delete()
                    j = j + 1
                End If
            Next
            Me.DataGrid2.Visible = True
        Catch ex As IndexOutOfRangeException
            MsgBox(ex.Message & "Seleccione una opción de búsqueda por campo", MsgBoxStyle.Critical, _
            "Aviso Al Usuario")
            Me.DataGrid2.Visible = False
        End Try
        Dim MiDataSetTemporal As New DataSet
        'Después de filtrar los registros encontrados, haremos 
        'una copia de esta tabla en MiDataSetTemporal.
        MiDataSetTemporal.Tables.Add(Me.MiDataset.Tables(CboLista.Text).Copy)
        'Para no modificar el contenido original de MiDataSet, 
        'cancelaremos los cambios efectuados más arriba.
        Me.MiDataset.Tables(CboLista.Text).RejectChanges()
        'Visualizamos los resultados, vaciando los registros 
        'de MiDataSetTemporal a la DataGrid2.
        Me.DataGrid2.DataSource = MiDataSetTemporal.Tables(CboLista.Text)
        'Contabilizamos los registros encontrados.
        Me.DataGrid2.CaptionText = MiDataSetTemporal.Tables(CboLista.Text).Rows.Count - _
        j & " registros encontados."
        'Cerramos o eliminamos MiDataSetTemporal.
        MiDataSetTemporal.Dispose()
    End Sub
    Public Sub MostrarColumnas(ByVal NombreTabla As String)
        For i = 0 To (MiDataset.Tables(NombreTabla).Columns.Count - 1)
            Me.ListBox1.Items.Add(MiDataset.Tables(NombreTabla).Columns.Item(i).Caption)
        Next
    End Sub

    Private Sub ChkTodos_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) _
        Handles ChkTodos.CheckedChanged
        If ChkTodos.Checked = True Then
            'Marcamos todos las casillas
            For i = 0 To Lstcolumnas.Items.Count - 1
                Lstcolumnas.SetItemChecked(i, True)
            Next
        Else
            'Desmarcamos todos las casillas
            For i = 0 To Lstcolumnas.Items.Count - 1
                Lstcolumnas.SetItemChecked(i, False)
            Next
        End If
    End Sub
    Private Sub TxtConsulta_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) _
        Handles TxtConsulta.TextChanged
        BtnTodos.Enabled = True
    End Sub

    Private Sub BtnMostrarColumnas_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
        Handles BtnMostrarColumnas.Click
        Dim NumeroColumnas As Integer
        Dim NombreColumnas As String
        GroupBox1.Enabled = True
        ChkTodos.Enabled = True
        NumeroColumnas = MiDataset.Tables(CboLista.Text).Columns.Count
        Lstcolumnas.Items.Clear()
        For i = 0 To (NumeroColumnas - 1)
            'Llenamos LstColumnas con todas los campos de la tabla seleccionada en CboLista.
            NombreColumnas = MiDataset.Tables(CboLista.Text).Columns.Item(i).Caption
            Lstcolumnas.Items.Add(NombreColumnas)
        Next
        DataGrid1.CaptionText = CboLista.Text
        BtnMostrarColumnas.Enabled = False
        BtnFiltrarColumnas.Enabled = True
        CboLista.Enabled = False
        ListBox1.Items.Clear()
        'Llamamos al procedimiento para llenar el ListBox1.
        MostrarColumnas(CboLista.Text)
    End Sub

    Private Sub BtnFiltrarColumnas_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
        Handles BtnFiltrarColumnas.Click
        BtnMostrarColumnas.Enabled = True
        BtnFiltrarColumnas.Enabled = False
        Dim opcion As String = CboLista.SelectedItem
        'Llenamos la DataGrid1 con los datos filtrados.
        DataGrid1.DataSource = Me.FiltrarDataSet()
        DataGrid1.DataMember = CboLista.Text
    End Sub
End Class

Aquí les muestro la interface de la aplicación, donde se puede observar todo los resultados.

Perxi_sistema-filtrado-busqueda.jpg

No olvides de darme tu voto en PanoramaBox, tu voto me motivará a desarrollar mejores aplicaciones. Gracias

Bueno, espero que les sea de utilidad la idea que aporté. Recuerden que "Hasta un programa perfecto tiene errores", si encuentras algunos errores o si tienes alguna idea para mejorar la aplicación...No dudes en escribirme al correo. Nos Vemos.

 


ir al índice

Fichero con el código de ejemplo: Perxi_sistema_filtrado_busqueda.zip - 16.1 KB