Para ilustrar los ejemplos, utilizaremos el siguiente dataset, llamado DStienda que contiene tablas de articulos, clientes y pedidos y un formulario de mantenimiento de pedidos pedidos_mant, que hemos creado arrastrando los elementos desde la pestaña Origenes de Datos de Visual Studio (Ver esquema)
En el formulario:
Dim artic As DSTienda.articulosRow = DS.articulos.NewRow() artic.articulo="003" artic.descri="Bota de fútbol" artic.estado="A" DSTienda.articulos.rows.Add(artic) 'También se puede hacer a través del bindingsource: ArticulosBindingSource.Add(artic)
Una alternativa es utilizar el método AddTABLArow que se crea automáticamente con cada datatable de nombre TABLA, y que recibe como parámetros los nombres de los campos del datatable
DSTienda.articulos.AddarticulosRow("C01","Chandal",1,23) DSTienda.estadosCliente.AddestadosClienteRow("A","Activo")
En el formulario:
' Carga todos los articulos de la BD en el datatable
ArticulosTableadapter.fill(DStienda.articulos)
Si la tabla de la BD tiene muchas filas, no se debe utilizar este sistema, por cuestiones de rendimiento, sino crear consultas SQL que filtren los datos que se quieren obtener, y hacer cargas parciales de información. Por ejemplo, si queremos cargar los articulos de una familia, creamos una consulta personalizada en articulosTableAdapter, que llamaremos “fillbyFamilia”:
' Carga los articulos de la familia escrita en familiatextbox
ArticulosTableadapter.fillbyfamilia(DStienda.articulos,familiatextbox.text)
Cada fila añadida, modificada o anulada en un datatable queda marcada cambiando su propiedad RowState. De esta forma se sabe si hay que hacer un Insert, Update o Delete al actualizar la base de datos. Para aplicar los cambios del datatable a la base de datos:
' Carga los articulos de la familia escrita en familiatextbox
ArticulosTableadapter.update(DStienda.articulos)
Si estamos en un formulario, antes de hacer el Update es necesario validar la fila que se esté editando:
Private Sub ArticulosBindingNavigatorSaveItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Me.Validate() ' Valida los datos del formulario ArticulosBindingSource.EndEdit() ' actualiza la fila en edición en el datatable ArticulosTableadapter.update(DStienda.articulos) ' actualiza los datos en la base de datos y ejecuta AcceptChanges End sub
Si queremos pasar un datatable a modo inserción (equivalente a pulsar el + en l bindingnavigator), podemos hacerlo mediante AddNew del bindingsource que está conectado a él:
sub button1_click(... clientesbingsource.Addnew() ' Equivale a pulsar el botón Añadir en el bindingnavigator end sub
Utilizaremos el evento TableNewRow del datatable.
Private Sub clientesDataTable_TableNewRow(ByVal sender As Object, ByVal e As DataTableNewRowEventArgs) ... e.row("estado")="A" ' Los clientes nuevos se crean en estado 'A' e.row("fec_alta")=date.now ' Fecha de alta =hoy End Sub
Los filtros y ordenación se hacen siempre mediante un bindingsource conectado a la datatable. De esta forma, podemos tener distintas “vistas” de los datos del datatable simultaneamente conectando varios bindingsource al mismo datatable, y todo ello sin alterar el contenido del mismo.
articulosbindingsource.filter="estado='A'" o articulosbindingsource.filter="codigo like '%" & textbusqueda.text & "%' and estado='A'"
Para desactivar el filtro, basta con asignarle “”. Importante: El filtro actúa sobre los datos del datatable, pero NO altera el contenido del mismo ni accede a base de datos. Cuando desactivamos el filtro podemos acceder de nuevo a todos los datos del datatable.
with articulosbindingsource .position = .find("articulo",textbox1.text) end with
La propiedad Current.Row del bindingsource me devuelve el DataRow activo, y a partir de ahí accedemos a los campos del mismo. Por ejemplo: si tenemos un Datagrid y queremos que al hacer doble-clic en una fila se abra un formulario para editar el articulo seleccionado, en el evento doble-clic del Datagrid pondremos algo así:
dim articuloactivo as DStienda.articulosRow with articulosbindingsource if .current isnot nothing then articuloactivo = .current.row EditarArticulo.editar(...articuloactivo.codigo) ' El formulario EditarArticulo tiene un método editar que recibe el código del articulo que se desea editar else MsgBox("No hay articulo en la selección") end if end with
La validación de datos de cada DataRow ha de hacerse siempre que se pueda en el Dataset, y así nos aseguramos de que siempre se hará, independientemente de que tengamos varios formularios para editar el mismo datatables. Utilizaremos el evento ColumnChanging del Datatable (haciendo doble clic en el campo que queremos validar del datatable, se genera el código del evento:
Private Sub clientesDataTable_ColumnChanging(ByVal sender As System.Object,e as DataColumnChangeEventArgs)... If (e.Column.ColumnName = "nif") Then If e.ProposedValue.ToString.Length <> 9 Then e.Row.SetColumnError("nif", "NIF Incorrecto") Else e.Row.SetColumnError("nif", "") End If End If End Sub
Otro ejemplo, con las lineas de un pedido, en el que al cambiar el código del artículo, asignamos el precio de la linea a partir del precio del articulo (suponemos que el datatable articulos ya está relleno con todos los articulos)
Private Sub pedlineasDataTable_ColumnChanging(ByVal sender As System.Object, ByVal e As DataColumnChangeEventArgs)... If (e.Column.ColumnName = Me.articuloColumn.ColumnName) Then ' busco el articulo y asigno el precio Dim art As articulosRow = CType(Me.DataSet, DSarticulos).articulos.FindByarticulo(e.ProposedValue) If art IsNot Nothing Then e.Row("precio") = art.precio e.Row.SetColumnError("articulo", "") Else e.Row.SetColumnError("articulo", "Articulo inexistente") e.ProposedValue = "" End If End If End Sub
Para que los mensajes de error se visualicen en el formulario, pondremos en éste un ErrorProvider conectado al Bindingsource que queramos.
Para hacer un formulario maestro-detalle tiene que haber un relación entro la tabla maestra y la de detalle . En nuestro ejemplo: pedidos→pedlineas. Vamos a hacer un formulario de edición de un pedido, que tiene los campos del datatable pedidos en la parte superior, y un grid de pedlineas en la parte inferior: