Una de las entradas de este blog que más visitas registra hace referencia a un error en el código generado de los TableAdapterManager, un componente de acceso a datos para usarlo junto con datasets tipados y sus respectivos tableadapters. Dicho error fue solucionado en el SP1 de Visual Studio y de las versiones Express, por lo que ya creía el tema olvidado. Sin embargo, parece que su uso despierta bastantes dudas, así que me vais a permitir que retome el tema con un pequeño ejemplo.
Un TableAdapterManager es un componente que se genera al crear un dataset tipado. Por lo tanto, si no usamos un dataset tipado ni necesitamos saber que tal cosa existe. Un TableAdapterManager automatiza el proceso de actualizar varias tablas relacionadas, manteniendo (o intentándolo) la integridad de los datos al hacer los update, insert y deletes en el orden apropiado. Hemos dicho que el TableAdapterManager se crea con un dataset tipado, por lo que sólo tendrá utilidad si este dataset tipado tiene varias tablas relacionadas.
Veamos el siguiente ejemplo, un dataset tipado, SeriesDataSet, con tres tablas: Series, Género y GeneroSerie. GeneroSerie es la tabla que permite la relación n:m entre géneros y series (una serie puede tener varios géneros, puede ser un drama romántico de ciencia ficción, por ejemplo).
SeriesDataSet
Vamos a suponer que tenemos un formulario donde el usuario podrá dar de alta, modificar y eliminar series y sus géneros. Es decir, variarán los datos de las datatables Series y GeneroSerie. A la hora de pasar esos cambios de datos a la base de datos debemos tener presente la relación de las tablas. Así, a la hora de insertar nuevas filas deberemos insertar primero las series y luego sus géneros, pero a la hora de borrar deberemos borrar primero los géneros de la serie y luego la serie. Esto significa que no podemos hacer un procedimiento genérico llamando alegremente a los métodos Update de los respectivos tableadapters. Pero podemos usar el método UpdateAll del TableAdapterManager y que sea él quien se coma el marrón. Algo así:
Public Function GuardaDatos(ByVal dsSeries As SeriesDataSet) As Integer Dim Result As Integer Dim tamSeries As New SeriesDataSetTableAdapters.TableAdapterManager Dim taSeries As New SeriesDataSetTableAdapters.SeriesTableAdapter Dim taGeneroSerie As New SeriesDataSetTableAdapters.GeneroSerieTableAdapter Using cnConexion As New SqlServerCe.SqlCeConnection( _ My.Settings.DefaultConnectionString) Try 'Le pasamos los TableAdapters al TableAdapterManager tamSeries.SeriesTableAdapter = taSeries tamSeries.GeneroSerieTableAdapter = taGeneroSerie 'Le pasamos la conexión que vamos a usar '(De no hacerlo, se crearía la suya propia) tamSeries.Connection = cnConexion 'Abrimos la conexión. En VB2008 sin SP1 daría error cnConexion.Open() Result = tamSeries.UpdateAll(dsSeries) Catch ex As Exception Throw ex Finally cnConexion.Close() End Try End Using Return Result End Function |
Resumiendo: hemos creado una instancia del TableAdapterManager que VB2008 ha creado junto con los tableadapters del dataset tipado SeriesDataSet. El TableAdapterManager necesita que le pasemos los tableadapters con los que va a trabajar, y eso es lo que hemos hecho. Como está tan tipado como el dataset, las datatables y los tableadapters, tiene tres propiedades distintas, cada una esperando su tableadapter. Habíamos dicho que sólo íbamos a modificar valores en la tabla SeriesDataTable y en la tabla GeneroSerieDataTable, por lo que sólo necesitamos sus dos tableadapters correspondientes. De GeneroTableAdapter aquí nos olvidamos.
Ya sólo nos queda llamar al método UpdateAll pasándole el dataset de Series y listo. El TableAdapterManager no tiene mucho más misterio. Básicamente trabajaremos únicamente con las propiedades de los respectivos tableadapters, el objeto Connection, el método UpdateAll y la propiedad UpdateOrder. UpdateOrder tiene dos valores posibles (y autoexplicativos): UpdateInsertDelete
(primero hace los update, luego los insert y por último los delete) e InsertUpdateDelete, que hace lo obvio. Podemos ver lo que hace el método UpdateAll, en todo caso, con el habitual «Ir a definición».
Y no hay más. Está bien para situaciones sencillitas, y se queda corto en otras. No lo he usado mucho, pero las veces que lo he metido me ha permitido ahorrarme un tiempecito que me ha venido bien para otras cosas.
Muy interesante, gracias por este artículo que realmente me ha sido útil.
Me alegro. Gracias por pasarte por aquí.