Las clases DataAdapter

Las clases DataAdapter

Como hemos comentado en anteriores apartados, los objetos DataAdapter (SqlDataAdapter y OleDbDataAdapter) van a desempeñar el papel de puente entre el origen de datos y el DataSet, permitiéndonos cargar el DataSet con la información de la fuente de datos, y posteriormente, actualizar el origen de datos con la información del DataSet.

Un objeto DataAdapter puede contener desde una sencilla sentencia SQL, como hemos visto en el apartado anterior, hasta varios objetos Command.

La clase DataAdapter dispone de cuatro propiedades, que nos van a permitir asignar a cada una, un objeto Command (SqlCommand u OleDbCommand) con las operaciones estándar de manipulación de datos. Estas propiedades son las siguientes.

• InsertCommand. Objeto de la clase Command, que se va a utilizar para realizar una inserción

de datos. • SelectCommand. Objeto de la clase Command que se va a utilizar para ejecutar una sentencia

Select de SQL. • UpdateCommand. Objeto de la clase Command que se va a utilizar para realizar una

modificación de los datos. • DeleteCommand. Objeto de la clase Command que se va a utilizar para realizar una

eliminación de datos. Un método destacable de las clases SqlDataAdapter/OleDbDataAdapter es el método Fill( ), que

ejecuta el comando de selección que se encuentra asociado a la propiedad SelectCommand, los datos obtenidos del origen de datos se cargarán en el objeto DataSet que pasamos por parámetro.

La Figura 344 muestra la relación entre los objetos DataAdapter y el objeto DataSet.

Figura 344. Relación entre objetos DataAdapter y DataSet.

© Grupo EIDOS 37. Conjuntos de datos y enlace (Data Binding)

Para demostrar el uso de los objetos DataAdapter vamos a desarrollar un proyecto con el nombre PruDataAdapter (hacer clic aquí para acceder a este ejemplo). En esta aplicación vamos a utilizar el mismo objeto DataAdapter para realizar una consulta contra una tabla e insertar nuevas filas en esa misma tabla.

En primer lugar diseñaremos el formulario del programa. Como novedad, introduciremos el control DataGrid, que trataremos con más profundidad en un próximo apartado. Baste decir por el momento, que a través del DataGrid visualizaremos una o varias tablas contenidas en un DataSet. La Figura 345 muestra el aspecto de esta aplicación en funcionamiento.

Figura 345. Formulario para operaciones con DataAdapter y DataGrid.

Respecto al código del formulario, en primer lugar, vamos a declarar varios objetos de acceso a datos

a nivel de la clase para poder tenerlos disponibles en diversos métodos. Veamos el Código fuente 569.

Imports System.Data.SqlClient

Public Class Form1 Inherits System.Windows.Forms.Form

Private oConexion As SqlConnection Private oDataSet As DataSet Private oDataAdapter As SqlDataAdapter

'.... '....

Código fuente 569

En el siguiente paso escribiremos el procedimiento del evento Load del formulario, y el método CargarDatos( ), que se ocupa de cargar el DataSet, y asignárselo al DataGrid a través de su propiedad DataSource. Observe el lector que en el método CargarDatos( ) lo primero que hacemos es vaciar el DataSet, puesto que este objeto conserva los datos de tablas y registros; en el caso de que no limpiáramos el DataSet, se acumularían las sucesivas operaciones de llenado de filas sobre la tabla que contiene. Veamos el Código fuente 570.

Programación con Visual Basic .NET © Grupo EIDOS

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load

' crear conexión oConexion = New SqlConnection() oConexion.ConnectionString = "Server=(local);Database=MUSICA;uid=sa;pwd=;"

' crear adaptador oDataAdapter = New SqlDataAdapter()

' crear comandos para inserción, consulta con sus parámetros ' y asignarlos al adaptador Dim oCmdInsercion As New SqlCommand("INSERT INTO AUTORES " & _

"(IDAutor,Autor) VALUES(@IDAutor,@Autor)", oConexion) oDataAdapter.InsertCommand = oCmdInsercion oDataAdapter.InsertCommand.Parameters.Add(New SqlParameter("@IDAutor",

SqlDbType.Int)) oDataAdapter.InsertCommand.Parameters.Add(New SqlParameter("@Autor", SqlDbType.NVarChar))

Dim oCmdConsulta As New SqlCommand("SELECT * FROM AUTORES", _ oConexion) oDataAdapter.SelectCommand = oCmdConsulta

' crear conjunto de datos oDataSet = New DataSet()

Me.CargarDatos() End Sub

Private Sub CargarDatos() ' vaciar el dataset oDataSet.Clear()

oConexion.Open() ' abrir conexión ' utilizar el adaptador para llenar el dataset con una tabla oDataAdapter.Fill(oDataSet, "Autores") oConexion.Close() ' cerrar conexión

' enlazar dataset con datagrid; ' en DataSource se asigna el dataset, ' en DataMember el nombre de la tabla del ' dataset que mostrará el datagrid Me.grdDatos.DataSource = oDataSet Me.grdDatos.DataMember = "Autores"

End Sub

Código fuente 570

Finalmente, en el botón Grabar, escribiremos las instrucciones para insertar un nuevo registro en la tabla. Veamos el Código fuente 571.

Private Sub btnGrabar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGrabar.Click

Dim iResultado As Integer

' asignar valores a los parámetros para el ' comando de inserción oDataAdapter.InsertCommand.Parameters("@IDAutor").Value = Me.txtIDAutor.Text oDataAdapter.InsertCommand.Parameters("@Autor").Value = Me.txtAutor.Text

© Grupo EIDOS 37. Conjuntos de datos y enlace (Data Binding)

' abrir conexión oConexion.Open() ' ejecutar comando de inserción del adaptador iResultado = oDataAdapter.InsertCommand.ExecuteNonQuery() ' cerrar conexión oConexion.Close()

Me.CargarDatos()

MessageBox.Show("Registros añadidos: " & iResultado)

End Sub

Código fuente 571

Navegación y edición de registros en modo desconectado

Anteriormente vimos la forma de realizar operaciones de edición, en modo conectado, sobre las tablas

de una base de datos, empleando los objetos Command. Pero como también ya sabemos, la arquitectura de ADO .NET está orientada a un modelo de trabajo

desconectado del almacén de datos, al que recurriremos sólo cuando necesitemos obtener los datos para su consulta y manipulación, o bien, cuando esos mismos datos desconectados, los hayamos modificado y tengamos que actualizarlos en la fuente de datos.

El objeto DataSet, combinado con un grupo de objetos enfocados al mantenimiento de datos desconectados, como son DataAdapter, DataTable, DataRow, etc., nos van a permitir realizar tareas como la navegación entre los registros de una tabla del DataSet, además de la modificación de sus datos en las operaciones habituales de inserción, modificación y borrado de filas.

El proyecto NavegaEdita que se acompaña como ejemplo (hacer clic aquí para acceder a este ejemplo), muestra los pasos necesarios que debemos dar para crear un sencillo mantenimiento de datos para una tabla albergada en un DataSet, junto a las típicas operaciones de navegación por las filas de dicha tabla. Seguidamente iremos desgranando el conjunto de pasos a realizar.

Partimos de una sencilla base de datos en SQL Server, que contiene la tabla Clientes, con los campos más característicos de esta entidad de datos: código cliente, nombre, fecha ingreso, crédito. Una vez creado un nuevo proyecto en VB.NET, diseñaremos el formulario de la aplicación que como vemos en la Figura 346, a través de sus controles, nos permitirá realizar las operaciones mencionadas.

Pasando a la escritura del código del programa, en primer lugar importaremos el espacio de nombres System.Data.SqlClient, y declararemos a nivel de clase un conjunto de variables para la manipulación

de los datos. Veamos el Código fuente 572.

Imports System.Data.SqlClient Public Class Form1

Inherits System.Windows.Forms.Form ' variables a nivel de clase para ' la manipulación de datos Private oDataAdapter As SqlDataAdapter Private oDataSet As DataSet Private iPosicFilaActual As Integer '.... '....

Código fuente 572

Programación con Visual Basic .NET © Grupo EIDOS

Figura 346. Formulario de navegación y edición manual de datos.

Como siguiente paso, escribiremos el manipulador del evento Load del formulario y un método para cargar los datos del registro actual en los controles del formulario, el Código fuente 573 muestra esta parte.

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load

' crear conexión Dim oConexion As SqlConnection oConexion = New SqlConnection() oConexion.ConnectionString = "Server=(local);" & _

"Database=Gestion;uid=sa;pwd=;"

' crear adaptador Me.oDataAdapter = New SqlDataAdapter("SELECT * FROM Clientes", _

oConexion)

' crear commandbuilder Dim oCommBuild As SqlCommandBuilder = New SqlCommandBuilder(oDataAdapter)

' crear dataset Me.oDataSet = New DataSet()

oConexion.Open() ' llenar con el adaptador el dataset Me.oDataAdapter.Fill(oDataSet, "Clientes") oConexion.Close()

' establecer el indicador del registro ' a mostrar de la tabla Me.iPosicFilaActual = 0

' cargar columnas del registro en ' los controles del formulario Me.CargarDatos()

End Sub

Private Sub CargarDatos()

© Grupo EIDOS 37. Conjuntos de datos y enlace (Data Binding)

' obtener un objeto con la fila actual Dim oDataRow As DataRow oDataRow = Me.oDataSet.Tables("Clientes").Rows(Me.iPosicFilaActual)

' cargar los controles del formulario con ' los valores de los campos del registro Me.txtIDCliente.Text = oDataRow("IDCliente") Me.txtNombre.Text = oDataRow("Nombre") Me.txtFIngreso.Text = oDataRow("FIngreso") Me.txtCredito.Text = oDataRow("Credito")

' mostrar la posición actual del registro ' y el número total del registros Me.lblRegistro.Text = "Registro: " & _

Me.iPosicFilaActual + 1 & " de " & _ Me.oDataSet.Tables("Clientes").Rows.Count

End Sub

Código fuente 573

Observe el lector que en el evento Load hemos creado un objeto CommandBuilder, pasándole como parámetro el DataAdapter. Como ya sabemos, un DataAdapter contiene una serie de objetos Command para las operaciones de consulta, inserción, etc. La misión en este caso del objeto CommandBuilder, es la de construir automáticamente tales comandos y asignárselos al DataAdapter, ahorrándonos ese trabajo de codificación.

En cuanto a las operaciones de navegación por la tabla, no hay un objeto, como ocurría con el Recordset de ADO, que disponga de métodos específicos de movimiento como MoveNext( ), MoveLast( ), etc. Lo que debemos hacer en ADO .NET, tal y como muestra el método CargarDatos(), es obtener del DataSet, la tabla que necesitemos mediante su colección Tables, y a su vez, a la colección Rows de esa tabla, pasarle el número de fila/registro al que vamos a desplazarnos. En nuestro ejemplo utilizaremos la variable iPosicFilaActual, definida a nivel de clase, para saber en todo momento, la fila de la tabla en la que nos encontramos.

El Código fuente 574 muestra el código de los botones de navegación, reunidos en el GroupBox Navegar, del formulario.

Private Sub btnAvanzar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAvanzar.Click

' si estamos en el último registro, ' no hacer movimiento If Me.iPosicFilaActual = _ (Me.oDataSet.Tables("Clientes").Rows.Count - 1) Then

MessageBox.Show("Último registro")

Else ' incrementar el marcador de registro ' y actualizar los controles con los ' datos del registro actual Me.iPosicFilaActual += 1 Me.CargarDatos()

End If

End Sub

Programación con Visual Basic .NET © Grupo EIDOS

Private Sub btnRetroceder_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnRetroceder.Click

' si estamos en el primer registro, ' no hacer movimiento If Me.iPosicFilaActual = 0 Then

MessageBox.Show("Primer registro")

Else ' disminuir el marcador de registro ' y actualizar los controles con los ' datos del registro actual Me.iPosicFilaActual -= 1 Me.CargarDatos()

End If

End Sub

Private Sub btnPrimero_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPrimero.Click

' establecer el marcador de registro en el primero Me.iPosicFilaActual = 0 Me.CargarDatos()

End Sub

Private Sub btnUltimo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnUltimo.Click

' establecer el marcador de registro en el primero ' obteniendo el número de filas que contiene la tabla menos uno Me.iPosicFilaActual = (Me.oDataSet.Tables("Clientes").Rows.Count - 1) Me.CargarDatos()

End Sub

Código fuente 574

Respecto a las operaciones de edición, debemos utilizar los miembros del objeto tabla del DataSet, como se muestra en el Código fuente 575. Una vez terminado el proceso de edición, actualizaremos el almacén de datos original con el contenido del DataSet, empleando el DataAdapter.

Private Sub btnInsertar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnInsertar.Click

Dim oDataRow As DataRow ' obtener un nuevo objeto fila de la tabla del dataset oDataRow = Me.oDataSet.Tables("Clientes").NewRow()

' asignar valor a los campos de la nueva fila oDataRow("IDCliente") = Me.txtIDCliente.Text oDataRow("Nombre") = Me.txtNombre.Text oDataRow("FIngreso") = Me.txtFIngreso.Text oDataRow("Credito") = Me.txtCredito.Text

' añadir el objeto fila a la colección de filas ' de la tabla del dataset Me.oDataSet.Tables("Clientes").Rows.Add(oDataRow)

End Sub

© Grupo EIDOS 37. Conjuntos de datos y enlace (Data Binding)

Private Sub btnModificar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnModificar.Click

Dim oDataRow As DataRow ' obtener el objeto fila de la tabla del dataset ' en el que estamos posicionados oDataRow = Me.oDataSet.Tables("Clientes").Rows(Me.iPosicFilaActual)

' modificar las columnas de la fila ' excepto la correspondiente al identificador cliente oDataRow("Nombre") = Me.txtNombre.Text oDataRow("FIngreso") = Me.txtFIngreso.Text oDataRow("Credito") = Me.txtCredito.Text

End Sub

Private Sub btnActualizar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnActualizar.Click

' actualizar los cambios realizados en el dataset ' contra la base de datos real Me.oDataAdapter.Update(Me.oDataSet, "Clientes")

End Sub

Código fuente 575

El caso del borrado de filas es algo diferente, por ello lo mostramos aparte del resto de operaciones de edición. En el Código fuente 576 vemos el código del botón Eliminar, dentro del cual, obtenemos la fila a borrar mediante un objeto DataRow, procediendo a su borrado con el método Delete( ). Para actualizar los borrados realizados, empleamos el método GetChanges( ) del objeto DataTable, obteniendo a su vez, un objeto tabla sólo con las filas borradas; información esta, que pasaremos al DataAdapter, para que actualice la información en el origen de datos.

Private Sub btnEliminar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnEliminar.Click

Dim oDataRow As DataRow ' obtener el objeto fila, de la tabla del dataset ' en el que estamos posicionados oDataRow = Me.oDataSet.Tables("Clientes").Rows(Me.iPosicFilaActual) oDataRow.Delete() ' borrar la fila

' mediante el método GetChanges(), obtenemos una tabla ' con las filas borradas Dim oTablaBorrados As DataTable oTablaBorrados =

Me.oDataSet.Tables("Clientes").GetChanges(DataRowState.Deleted)

' actualizar en el almacén de datos las filas borradas Me.oDataAdapter.Update(oTablaBorrados)

' confirmar los cambios realizados Me.oDataSet.Tables("Clientes").AcceptChanges()

' reposicionar en la primera fila Me.btnPrimero.PerformClick()

End Sub

Código fuente 576

Programación con Visual Basic .NET © Grupo EIDOS