Generando una solución con AjGenesis usando archivos hbm de NHibernate

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

This entry was posted in 1389, 2643, 4752, 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>