Hace unos meses, escribí un ejemplo de generación de código que usa los archivos .hbm como modelo inicial:
Generating Code with AjGenesis Using NHibernate Hbm Files
Generando código con AjGenesis usando archivos de mapeo de NHibernate
Ya conocen que AjGenesis puede usar como modelo lo que uno decida. Prefiero un modelo libre, pero, según el bueno de Fabio Maulo, “los archivos hbm los usan un montón de gente”. Estos ejemplos me sirven también para demostrar que se puede usar un modelo distinto de los que propongo en otros ejemplos.
Desde esos posts, he mejorado el ejemplo. Pueden bajarlo del trunk del proyecto en Codeplex:
i
Como lo mío es un apostolado, les dejo preparado un paquete listo para ejecutar, en mi Skydrive, que incluye el ejemplo y los binarios de AjGenesis en desarrollo:
Examples > AjGenesis > NHibernateMappingExample02.zip
Esta es su estructura de directorios:
Hay dos proyectos: AjFirstExample, y AjTest. El primero tiene solamente dos simples entidades. El segundo tiene más entidades, con relaciones uno a varios. Pueden generar el código para una solución completa, lanzando los comandos:
GenerateAjFirstExample.cmd
GenerateAjTest.cmd
Son simples “shortcuts” para los comandos
GenerateProject AjFirstExample
GenerateProject AjTest
Como ejemplo, esta es la solución que genera para el proyecto AjTest (ver que queda dentro de un directorio Build, que si no existe lo crea):
Pueden ejecutar el sitio web (el script para generar la base de datos, está dentro del directorio Sql de cada proyecto, ej Projects\AjTest\Sql):
En este ejemplo, uso los archivos .hbm como modelo. Lo nuevo del ejemplo, es que enriquecí el modelo con el uso de tags meta, como en este Employee.hbm de AjTest:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
assembly="AjTest.Entities"
namespace="AjTest.Entities"
>
<class name="Employee" table="employees">
<meta attribute="SetName">Employees</meta>
<meta attribute="Descriptor">Employee</meta>
<meta attribute="SetDescriptor">Employees</meta>
<id name="Id" column="Id" type="Int32">
<meta attribute="Description">Id</meta>
<generator class="native"/>
</id>
<property name="EmployeeCode" type="String">
<meta attribute="Description">Employee Code</meta>
</property>
<property name="LastName" type="String">
<meta attribute="Description">Last Name</meta>
</property>
<property name="FirstName" type="String">
<meta attribute="Description">First Name</meta>
</property>
<many-to-one name="Department" column="IdDepartment"
class="AjTest.Entities.Department, AjTest.Entities" />
<bag name="Tasks" lazy="true" inverse="true" cascade="all">
<key column="IdEmployee"/>
<one-to-many class="AjTest.Entities.Task, AjTest.Entities"/>
</bag>
<bag name="EmployeeSkills" lazy="true" inverse="true" cascade="all">
<key column="IdEmployee"/>
<one-to-many class="AjTest.Entities.EmployeeSkill, AjTest.Entities"/>
</bag>
</class>
</hibernate-mapping>
Note the use of the meta tag at class level, and at property level. AjGenesis run tasks, one is Tasks\LoadMappings.ajg:
include "Utilities/Utilities.tpl"
include "Utilities/FileUtilities.tpl"
include "Utilities/TypeUtilities.tpl"
Include("Utilities/NHibernateUtilities.tpl")
include "Templates/CSharp/UtilitiesCs.tpl"
include "Templates/CSharp/CSharpFunctions.tpl"
AssemblyManager.LoadFrom("Libraries/NHibernate.dll")
parser = new NHibernate.Cfg.MappingSchema.MappingDocumentParser()
if not Project.BuildDir then
Project.BuildDir = "Build/${Project.Name}/CSharp"
end if
Project.Entities = CreateList()
for each MappingName in Project.Mappings
filename = "Projects/${Project.Name}/Mappings/${MappingName}.hbm.xml"
mapping = parser.Parse(OpenAsStream(filename))
for each hbmclass in mapping.Items where IsType(hbmclass, "HbmClass")
Entity = CreateObject()
Project.Entities.Add(Entity)
Entity.ClassName = hbmclass.name
Entity.Name = hbmclass.name
Entity.Namespace = mapping.namespace
Message "Processing Mapping of Entity " & Entity.Name
Entity.Properties = CreateList()
if hbmclass.Id then
Property = CreateObject()
Property.Name = hbmclass.Id.name
Property.Type = HbmTypeToCSharp(hbmclass.Id.type1, Entity.Namespace)
Property.IsId = True
for each meta in hbmclass.Id.meta
Property.SetValue(meta.attribute, meta.GetText())
end for
Entity.Properties.Add(Property)
end if
for each meta in hbmclass.meta
Entity.SetValue(meta.attribute, meta.GetText())
end for
for each item in hbmclass.Items
Message "Processing Item " & item.GetType().Name
if IsType(item, "HbmProperty") then
Property = CreateObject()
Property.Name = item.name
Property.SetValue("Description", "Description " & item.name)
Property.Type = HbmTypeToCSharp(item.type1, Entity.Namespace)
Entity.Properties.Add(Property)
for each meta in item.meta
Property.SetValue(meta.attribute, meta.GetText())
end for
end if
if IsType(item, "HbmManyToOne") then
Property = CreateObject()
Property.Name = item.name
Property.Type = HbmTypeToCSharp(item.class, Entity.Namespace)
Property.Reference = HbmTypeToCSharp(item.class, Entity.Namespace)
Entity.Properties.Add(Property)
end if
if IsType(item, "HbmSet") then
Property = CreateObject()
Property.Name = item.name
Property.IsSet = true
Property.Type = HbmTypeToCSharp(item.Item.class, Entity.Namespace)
Entity.Properties.Add(Property)
end if
if IsType(item, "HbmBag") then
Property = CreateObject()
Property.Name = item.name
Property.IsList = true
Property.Type = HbmTypeToCSharp(item.Item.class, Entity.Namespace)
Entity.Properties.Add(Property)
end if
end for
end for
end for
Noten el uso de Property.SetValue(…), Entity.SetValue(…) para enriquecer el modelo en-memoria con la nueva metadata contenida en los archivos de mapeo. Cualquier dato simple que en anteriores ejemplos ponía en los modelos libres, ahora puede estar en el hbm. Como en otros ejemplos de AjGenesis, uso la metadata para mostrar leyendas, textos en la presentación, o para tomar decisiones o usarlas como quiera en las tareas y templates.
Este es un ejemplo “proof-of-concept”. Debería ser mejorado para usar todo el poder de NHibernate. Pero es una demostración de un modelo inicial, para crear gran cantidad de artefactos de textos, en este caso, una aplicación lista para ejecutar y extender.
Tengo que escribir más ejemplos, volviendo a usar un modelo libre, como adelanté en:
AjGenetizando una aplicación
Nos leemos!
Angel “Java” Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez