====== FAQ ====== 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 ([[.:ado_esquema|Ver esquema]]) ==== Cómo añadir elementos a un datatable manualmente ==== 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") ==== Cómo llenar un datatable desde la base de datos ==== 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": - Abrimos el dataset - Con el botón derecho en articulosTablesAdapter, "Agregar Consulta"->"...SQL"->"SELECT que devuelve filas" - Completamos la SQL: "select ... from articulos where familia=? order by familia" y pulsamos "Siguiente" - Cambiamos el nombre por "fillbyfamilia", quitamos la marca a "Devolver un Datatable" y le damos a Siguiente - Finalizar ' Carga los articulos de la familia escrita en familiatextbox ArticulosTableadapter.fillbyfamilia(DStienda.articulos,familiatextbox.text) ==== Cómo actualizar la base de datos desde un datatable ==== 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 ==== Cómo pasar el datatable a modo inserción ==== 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 ==== Cómo asignar valores por defecto a una fila nueva ==== 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 ==== Cómo aplicar un filtro ==== 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. ==== Cómo localizar una fila y posicionarse en ella ==== with articulosbindingsource .position = .find("articulo",textbox1.text) end with ==== Cómo acceder a los datos de la posición actual de un Bindingsource ==== 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 ==== Cómo validar datos ==== 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 * e.Column me devuelve la columna que se está cambiando * e.proposedvalue es el valor que se quiere asignar a la columna (el que hay que validar) * e.Row me devuelve la datarow activa. Esto me permite asignar valores a otros datos en función del que está cambiando. * Para asignar un mensaje de error a una columna, utilizamos e.Row.SetColumnError(columna, mensaje) * 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 * Me.Dataset es el dataset al que pertenece este datatable. Hacemos el casting para acceder más comodamente a articulos, pero podriamos haberlo hecho poniendo Me.dataset.tables("articulos") * Cada datatable tiene un método llamado FindByXXXXX(valor) para localizar filas en él accediendo por la primera key Para que los mensajes de error se visualicen en el formulario, pondremos en éste un **ErrorProvider** conectado al Bindingsource que queramos. ==== Cómo crear un formulario maestro-detalle ==== 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: * Creamos la parte de la cabecera (pedidos), arrastrando los campos que queramos * Arrastramos pedlineas al formulario para crear el grid, pero **cogiendo el que hay dentro de pedidos, no el que aparece a primer nivel**. De esta forma, el pedlineasbindingsource no se conecta directamente al datatable pedlineas, sino que lo hace a la relación entre pedidos y pedlineas, y así tendremos que: * Cuando en pedidos estemos situados en un pedido determinado, en el grid solamente se mostrarán las lineas de ese pedido * Si cambiamos de posición en pedidosbindingsource, el grid se refrescará automáticamente * Cuando añadimos una nueva linea a pedlineas, el campo pedido se asigna automáticamente al código de pedido de la cabecera