(No, no me he equivocado quería escribir autoMÁGICOS no automáticos :P el porqué ya ser verá en el post)
Hace un par de semanas me mandó un mail un lector del blog (Germán) comentándome una duda con el uso de Datasets tipados como origen de datos en Windows Forms.
Dado que ya me había pasado algo similar en algún proyecto en el que trabajé pero del que no recuerdo cómo lo solucionamos, decidí ponerme manos a la obra para hacer un proyecto que tenga la problemática que me planteó Germán y tratar de encontrar una solución óptima. Y como le comenté a Germán, lo pongo aquí para que le sirva a más gente ;) Vamos a empezar:
Tenemos una base de datos a la que llamaré PRUEBAS, con únicamente 2 tablas: Pedido y DetallePedido, con el siguiente esquema:
Pedido
id -Identity PRIMARY_KEY
Descripcion -Varchar(10)
DetallePedidoidDetalle - Identity PRIMARY_KEY
idPedido - Int
Cantidad - Int
Precio - Float
Típicas tablas maestro-detalle, relacionadas por Pedido.id – DetallePedido.idPedido
Creamos un proyecto Windows Form en Visual Studio 2005, y añadimos un Dataset donde agregamos las 2 tablas, que nos quedará de la siguiente forma:
Ahora nos vamos al formulario, y desde el explorador de Origenes de Datos, arrastramos los campos de la tabla Pedidos y los relacionados de DetallesPedido (Atención: tiene que ser el que cuelga de Pedido para que nos mantenga la relación)
Con lo que el formulario nos quedará más o menos así:
Ahora nos vamos a código y buscamos el evento pedidoBindingNavigatorSaveItem_Click que es el que se produce cuando presionamos el botón de Guardar Cambios, y añadimos las 2 líneas en rojo para que guarde también las líneas de detalle:
private void pedidoBindingNavigatorSaveItem_Click(object sender, EventArgs e)
{
this.Validate();
this.pedidoBindingSource.EndEdit();
this.pedidoTableAdapter.Update(this.dataSet1.Pedido);
this.detalle_PedidoBindingSource.EndEdit();
this.detalle_PedidoTableAdapter.Update(this.dataSet1.Detalle_Pedido);
}
Si lo probamos debería funcionar perfectamente, permitiendo movernos entre registros, agregar nuevos pedidos y sus líneas de detalle correspondientes. Ahora viene el problema que nos plantea Germán, ¿y si hay 2 usuarios añadiendo pedidos a la vez?
Pues vamos a probarlo, compilamos, arrancamos 2 veces el ejecutable y creamos un nuevo pedido en cada instancia. ¿Qué sucede? Como es normal asigna un valor al campo id del pedido, que obtiene de sumarle 1 al último valor más grande que exista en la tabla ese momento (ojo: no es el valor que le corresponda al IDENTITY) con lo que nos dará el mismo valor para las 2 instancias.
No vamos a hacer nada más por ahora, guardamos y vemos que pasa.
Como es normal nos ha actualizado el id del pedido con el valor que le ha asignado en la tabla de la base de datos. Bien, es el comportamiento normal y esperado.
Vale, ahora vamos a introducir líneas en estos 2 pedidos que acabamos de guardar:
Como en el caso de las cabeceras de pedido, nos asigna un valor al campo idDetalle, que vuelve a ser el valor máximo del campo en la tabla sumándole 1, con lo que vuelve a ser el mismo valor para las 2 instancias. Guardamos y nos asigna el valor que le corresponde en la tabla.
Vale, todo va bien, hemos añadido una cabecera y una línea y no hay ningún problema, ¿seguro que no hay problemas?
Vamos a hacer lo mismo que antes pero cambiando un poco la forma de hacerlo, ahora vamos a guardar después de añadir la línea de detalle, a ver qué pasa.
Vaya sorpresa, nos ha desaparecido la línea del 2º pedido que guardemos, ahora si nos movemos por los registros esa línea no aparece en ninguna de las 2 instancias, pero si nos vamos a la tabla veremos que está con el identificador que le asignó a la primera instancia que se guardó.
Si cerramos los formularios y volvemos a abrirlos nos encontraremos un pedido con 2 líneas y otro sin líneas. Esto se debe a que al asignar el valor del identificador a las cabeceras también lo hace con las líneas, pero al guardar no actualiza el identificador del pedido en las líneas, con lo que se queda el que tenía en un principio ... ups, vaya lío que hemos montado, ¿no?
Bueno, creo que ya se puede ver por donde van los tiros: ¿nos fiamos o no nos fiamos del código generado automáticamente al arrastar elementos desde los orígenes de datos?
Como este post ya es bastante largo, os presentaré más cosas sobre DataBinding, más problemas y cómo solucionarlos en un próximo post, permanecer atentos al blog :)