AjGenesis: Modelo desde la Base de Datos

AjGenesis se caracteriza por partir de uno o varios modelos, libres de definición, para generar artefactos de texto, usando tareas y plantillas programables. Cuando inicié el proyecto, recuerdo haber leído el libro de Kathleen Dollard Code Generation in Microsoft .NET

Una de las recomendaciones de la buena de Dollard, es tomar metadata de algún lugar, por ejemplo la base. Como no creo que toda la metadata esté en alguna parte, me incliné desde el principio por un modelo libre (también me aparté rápidamente del camino de Dollard, basado en generar código basado en transformaciones de XSLT, que es el “camino del diablo”, no lo intenten en sus casas, sin avisar a sus padres…;-). Hay varios puntos que me interesaron de la postura de Dollard, será cuestión de escribir más adelante un post comentando el libro.

Pero no hay que descartar el tomar metadata, información que nos pueda servir, de otras fuentes, la más común es la base de datos que tengamos entre manos. Recordemos que la generación de código es una solución pragmática, no debemos dejar de usar lo que nos resulte conveniente para el proyecto en el que estemos trabajando.

Así que ya hace unos meses, puse un pequeño ejemplo dentro de los que vienen en el AjGenesis. Pueden verlo en la

AjGenesis Versión 0.5

Está en la carpeta examples\LoadDB.

Trabaja como ejemplo de consulta de esquema contra una base Northwind que tengamos en nuestro MS SQL Server. Desde ese directorio, en una línea de comando, ejecutamos

make

Este comando ejecuta una tarea de AjGenesis:

..\..\bin\AjGenesis.Console Tasks\DbProcess.ajg
pause

Se conecta a la base:

PrintLine "Connection" AssemblyManager.LoadWithPartialName("System.Data") con = new System.Data.SqlClient.SqlConnection() PrintLine "ConnectionString" con.ConnectionString = "server=(local);uid=sa;database=Northwind" PrintLine "Command" cmd = new System.Data.SqlClient.SqlCommand() cmd.Connection = con cmd.CommandText = "select * from Information_Schema.Tables" con.Open()

Uso la información que está en Information_Schema.Tables. Observen el uso del nuevo AssemblyManager, que permite cargar assemblies (tendría que revisar si es necesario cargar el System.Data, y si puedo dejar de usar LoadWithPartialName que ahora en .NET 2.0 está “deprecated”)

Luego, consigue los nombres de las tablas:

dr = cmd.ExecuteReader() TableNames = new System.Collections.ArrayList() while dr.Read() PrintLine "Table " & dr.Item("Table_Name") & ": " & dr.Item("Table_Type") TableName = dr.Item("Table_Name") if dr.Item("Table_Type")="BASE TABLE" then TableNames.Add(TableName) end if end while dr.Close()

Una vez conseguida esa información, obtiene las columnas de las tablas, armando un modelo en memoria, en una collección Tables:

 

Tables = new System.Collections.ArrayList() For each TableName in TableNames PrintLine "Loading Table " & TableName Table = new AjGenesis.Models.DynamicModel.DynamicObject() Table.Name = TableName Table.Columns = new System.Collections.ArrayList() cmd.CommandText = "SELECT * from Information_Schema.Columns where Table_name='" & TableName & "'" dr = cmd.ExecuteReader() while dr.Read() ColumnName = dr.Item("Column_Name") PrintLine "Processing Column " & ColumnName & ": " & dr.Item("Data_Type") Column = new AjGenesis.Models.DynamicModel.DynamicObject() Column.Name = ColumnName Column.DataType = dr.Item("Data_Type") if dr.Item("Character_Maximum_Length") then Column.Length = dr.Item("Character_Maximum_Length") Column.IsNumeric = false else if dr.Item("Numeric_Precision") then Column.Length = dr.Item("Numeric_Precision") Column.Scale = dr.Item("Numeric_Scale") Column.IsNumeric = true end if end if Column.SqlName = Column.Name Column.Name = Column.Name.Replace(" ","") Table.Columns.Add(Column) end while dr.Close() Table.SqlName = Table.Name Table.Name = Table.Name.Replace(" ","") Tables.Add(Table) end for

Finalmente, hace el viejo truco de recorrer ese modelo, y aplicarle un template, para generar otro modelo (recuerde esta capacidad del proyecto: un modelo puede ser un XML, serializado en archivo de texto, entonces, un proceso de generación puede generar otro modelo para usar o retocar más adelante):

FileManager.CreateDirectory("Model") for each Table in Tables TransformerManager.Transform("Templates\Table.tpl", "Model\${Table.Name}.xml", Environment) end for

Un ejemplo de modelo generado:

 

<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?> <Table> <Name>Region</Name> <SqlName>Region</SqlName> <Columns> <Column> <Name>RegionID</Name> <SqlName>RegionID</SqlName> <DataType>int</DataType> <Length></Length> <Scale></Scale> </Column> <Column> <Name>RegionDescription</Name> <SqlName>RegionDescription</SqlName> <DataType>nchar</DataType> <Length>50</Length> <Scale></Scale> </Column> </Columns> </Table>

Ahora, con el AssemblyManager, se podría tomar una .dll cualquiera y cargarla, para usarla en nuestra generación (tengo que postear sobre el uso que le dió el bueno de Darío Quintana a esta “feature”, ver Generando con AjGenesis desde los assemblies). Me imagino que podemos usar, por ejemplo, la librería Meta de MyGenerationSoftware para conseguir metadata de cualquier base de datos. Vean también que está disponible el código fuente de ese utilitario.


Nos leemos!


Angel “Java” Lopez
http://www.ajlopez.com/

This entry was posted in 2643, 3463, 5124, 6145. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>