Entre unas cosas y otras tengo ambos blogs casi abandonados: ando muy liado en el curro (inventario, programas de CNC y una aplicación para fábrica), voy a comprarme un coche y los últimos fines de semana (cuando más escribo) no los he pasado en casa. Tengo una entrada casi terminada sobre un par de cositas sobre Visual Basic 2008 y mi aplicación Colección Anime, pero antes he tenido que solucionar un problema que me ha llevado cuatro horas entender y 10 minutos corregir. Lo posteo por si a alguien le pasa y pudiera encontrarlo útil.
Visual Basic 2008 trae un nuevo componente de acceso a datos llamado TableAdapterManager. En teoría debe simplificarnos el actualizar una base de datos partiendo de un dataset tipado con varias tablas relacionadas. El TableAdapterManager tiene un método, UpdateAll, que guarda los datos de todas las tablas del dataset (filas añadidas, modificadas y eliminadas) en el orden correcto, respetando las relaciones. En teoría debería simplificarnos las operaciones de guardado de datos en estos casos. En la práctica no es tan simple y me he encontrado con una serie de problemas. La documentación es bastante escasa, así que me ha tocado descifrar el código y ver qué hace realmente el dichoso componente.
La situación inicial es ésta: una clase de acceso a datos con un método llamado GuardarDatos que prepara el café, digo, guarda los datos. El dataset tipado cuenta con tres tablas (Series, Géneros y Géneros de serie) de las cuales, en principio, sólo se modificarán (aquí) la primera y la última, ya que de Géneros me ocupé en TablasMenores.
Los problemas que se presentaron fueron los siguientes:
-
La conexión no puede estar abierta. En mi forma actual de hacer las cosas, uso un objeto conexión (que puede ser en combinación con un bloque Using o no, según las circunstancias) en lugar del objeto conexión propio del TableAdapter. Con el TableAdapterManager intenté hacer lo mismo, esto es, le asigno el objeto conexión mediante la propiedad Connection, abro la conexión, hago lo que tenga que hacer (en este caso, sólo el UpdateAll del TableAdapterManager), cierro la conexión y a otra cosa. Esto me dio error, porque el TableAdapterManager intenta abrir la conexión sin comprobar si ya está abierta. También se encarga de cerrarla cuando termina.
-
Necesita TableAdapters. Vale, esto es lógico: internamente llama a los distintos TableAdapter para acceder a la base de datos. El problema es que si no hay, no los instancia. En el método UpdateAll comprueba si cada TableAdapter es Nothing y si lo es, se salta el código referente a ese TableAdapter. Esto tiene su parte interesante, pues podemos discriminar qué tablas vamos a actualizar y cuáles no, pero no he encontrado que se comente esto en la documentación, y me ha llevado un rato encontrar qué era lo que fallaba. La solución es simple: instanciar los TableAdapter necesarios y pasárselos a las respectivas propiedades que tiene el TableAdapterManager, algo así: tamSeries.SeriesTableAdapter = taSeries. Internamente el TableAdapterManager pasa su objeto Connection a cada TableAdapter que vaya a usar.
-
El tercer problema no ha sido del TableAdapterManager sino mío, al creer que un Remove y un Delete son lo mismo. Resulta que al borrar los distintos géneros de una serie usaba el método RemoveGeneroSerieRow que se había generado con el DataTable tipado. Al ejecutar el UpdateAll del TableAdapterManager me daba un error por violación de clave externa. Revisando la documentación me encuentro con que al hacer un Remove eliminamos la fila y aceptamos los cambios, por lo que esa información no pasa a la base de datos. Lo correcto es hacer un Delete, que nos marca la fila para borrado. El lío viene porque tenemos un método RemoveMiFilaRow en el DataTable, pero no un DeleteMiFilaRow, así que hay que buscar la fila (con el método FindByMiClavePrincipal, por ejemplo) y usar su método Delete.
No he puesto código de ejemplo. Si alguien lo necesita, sólo tiene que pedirlo.
Nos vemos en el Forlon.
Hola por favor me podrias ayudar con el codigo de los problemas de los tableadaptermanager parece que yo tengo el mismo problema y estoy iniciando en esto y se me heca muy complicado
No problem. Te he mandado un correo para hablar más tranquilamente del asunto.
me puedes compartir tu codigo de ejemplo plis
saludos desde tj BC mexico
Hola, estoy haciendo miks primeros pasos en VB 2008 y me encontre con el problema que tu ya has resuelto. Podrìas compartir el codigo al que haces referencia.-
Gracias
Omar
El código está en esta entrada. Te recomiendo que actualices tu VB, porque a partir del SP1 de Visual Studio 2008 (y del SP1 de las correspondientes versiones Express) el problema está resuelto.
Hola sabes yo estoy empezando a ver este tema y me seria muy util ver tu ejemplo para poder empezar te agradeceria q me lo mandaras ———————-
He añadido un fragmento de código donde se utiliza un TableAdapterManager. Básicamente, es el que se menciona aquí. Lo podéis ver en esta entrada
QUISIERA ME AYUDARAS…TENGO UN PROGRAMA EN VISUAL ESTUDIO 2010 ENLAZADO A DATOS, EL DISEÑADOR DEL DATASET AUTOMATICAMENTE ME GENERA UN INSERT INTO Y UN SELECT, PERO NO ME GENERA LOS METODOS UPDATE Y DELETE ..???… QUE TENGO QUE HACER PARA QUE ME GENERE AUTOMATICAMENTE LOS METODOS QUE ME FALTAN EN EL DISEÑADOR DEL DATASET…????
Es la primera vez que veo ese problema, así que no sé qué decirte (salvo que si lo que te «traes» es una vista y no una tabla, puede ser esa la razón). Puedes, eso sí, añadir a mano esas consultas en el diseñador del Dataset, seleccionando el TableAdapter correspondiente. En la sección de Propiedades tienes todas las consultas generadas y puedes modificarlas o añadir otras.
perdona, tal vez se me olvido comentar, que lo que abro es una tabla de access 2003 con visual studio 2010 y que al estar configurando el dataset solo me genera los metodos insert into y select…mas no los metodos update y y delete…….
SIR… CUBANO…..YA QUEDOOOOOOOOOOOOOOO……………….GRACIAS A UN DOCUMENTO QUE ENCONTRE POR LA TELARAAÑÑÑAAAAA……JAJAJA..
Comentarte que he experimentado problemas similares a los tuyos y en concreto el último me llevaba de cabeza. Muchas gracias por escribir la solución ya que no creo que sea el único que tenga este problema, de hecho, si la inserción se realiza y guarda en el origen de datos correctamente con .AddRow(), no resulta intuitivo que no exista un .DeleteRow().
Saludos.