Generando código para NHibernate (Parte 2)

Published on Author lopez5 Comments

Gracias a una iniciativa del bueno de Omar del valle Rodriguez comencé a escribir un ejemplo con AjGenesis, para generar código .NET que use NHibernate (ver Generando código para NHibernate (Parte 1)). Ya tenía ejemplos con y sin NHibernate (ver ….) pero esta vez, Omar pidió un modelo con herencia. Pueden descargar esta primera versión como AjOmar-v1.0.zip desde los ejemplos del proyecto en Codeplex.

Usé la versión 0.5 de AjGenesis, a descargar desde CodePlex. Si Ud. tiene la versión 0.4.3, debería funcionar sobre este ejemplo, pero no la he probado.

El modelo

Ahora tengo una primera versión de lo pedido por Omar. El “leit-motiv” del AjGenesis, es basarse en un modelo definible libremente, y desde ahí, ir generando código, scripts de base de datos, artefactos de textos, archivos de solución, proyectos, lo que uno quiera.

En el modelo Projects\AjOmar\Project.xml he definido:

<Project> <Name>AjOmar</Name> <Description>Example AjOmar for (N)Hibernate</Description> <Prefix>AjOm</Prefix> <Domain>com.ajomar</Domain> <CompanyName>ajomar</CompanyName> <Model> <Entities> <Entity Source="Entities/Client.xml"/> <Entity Source="Entities/Company.xml"/> <Entity Source="Entities/User.xml"/> </Entities> </Model> </Project>

Para entender algo más sobre el modelo y la generación, ver Hello World con AjGenesis.

En el modelo coloqué tres entidades: Client, Company, User, que es lo que pedía Omar. En Client, tengo:

<Entity> <Name>Client</Name> <Description>Client Entity</Description> <SetName>Clients</SetName> <Descriptor>Client</Descriptor> <SetDescriptor>Clients</SetDescriptor> <SqlTable>clients</SqlTable> <Properties> <Property> <Name>Id</Name> <Type>Id</Type> </Property> <Property> <Name>PhysicalAddress</Name> <Type>Text</Type> <SqlType>varchar(200)</SqlType> </Property> <Property> <Name>ContactEmail</Name> <Type>Text</Type> <SqlType>varchar(200)</SqlType> </Property> <Property> <Name>RegisterDate</Name> <Type>DateTime</Type> <SqlType>datetime</SqlType> </Property> <Property> <Name>Active</Name> <Type>Boolean</Type> <SqlType>bit</SqlType> </Property> </Properties> </Entity>

Los campos son los pedidos por Omar, pero todavía con tipos y nombres SQL que elegí yo. Client es la clase madre de Company y de User. En el Company.xml tenemos:

 

<Entity> <Name>Company</Name> <Description>Company Entity</Description> <SetName>Companies</SetName> <Descriptor>Company</Descriptor> <SetDescriptor>Companies</SetDescriptor> <SqlTable>companies</SqlTable> <Inherits>Client</Inherits> <Properties> <Property> <Name>CompanyName</Name> <Type>Text</Type> <SqlType>varchar(200)</SqlType> </Property> <Property> <Name>ContactName</Name> <Type>Text</Type> <SqlType>varchar(200)</SqlType> </Property> </Properties> </Entity>

Para los que vieron anteriores ejemplos, lo nuevo es el <Inherits>Client</Inherits>. Esto indica que esta entidad “hereda” de la entidad Client, en el dominio a generar. Lo mismo puse en User.xml:

<Entity> <Name>User</Name> <Description>User Entity</Description> <SetName>Users</SetName> <Descriptor>User</Descriptor> <SetDescriptor>Users</SetDescriptor> <SqlTable>users</SqlTable> <Inherits>Client</Inherits> <Properties> <Property> <Name>FirstName</Name> <Type>Text</Type> <SqlType>varchar(200)</SqlType> </Property> <Property> <Name>LastName</Name> <Type>Text</Type> <SqlType>varchar(200)</SqlType> </Property> </Properties> </Entity>

En el subdirectorio Projects\AjOmar\Technologies, encontramos los archivos CSharp2Nh.xml y VbNet2Nh.xml. Veamos el primero:

 

<Technology> <Programming> <Dialect>CSharp2Nh</Dialect> </Programming> <Database> <Dialect>MsSql</Dialect> <Name>AjOmar</Name> <Username>sa</Username> <Prefix>ajom_</Prefix> <Host>(local)</Host> </Database> <NHibernate> <Dialect>NHibernate.Dialect.MsSql2000Dialect</Dialect> </NHibernate> </Technology>

Vean que ahí se establece el usuario y contraseña para usar contra un SQL Server. Si quieren, lo modifican acá. Sino, como alternativa, pueden luego modificar el web.config de la solución generada. El ejemplo también instala base, pero esto es opcional: genera un archivo con los scripts de creación, que Uds. puede correr en cualquier momento manualmente contra el SQL Server que elijan.

Generando el código

Para generar el código, seguir los siguientes pasos:

  1. Editar los parámetros del SQL Server que están en los archivos de tecnología mostrados arriba
  2. Ir a la línea de comando.
  3. Agregar al PATH el directorio \bin del AjGenesis 0.5 bajado
  4. Ir al directorio AjOmar del ejemplo bajado
  5. Ejecutar

    GenerateProject AjOmar CSharp2Nh

    para generar el ejemplo en C Sharp 2.

  6. Ejecutar

    DeployDatabase AjOmar CSharp2Nh

    para crear la base en el SQL Server local (en caso de querer hacerlo manualmente ver el código generado para crear la base en Build\AjOmar\CSharp2Nh\Sql)

  7. Si desea generar el código para VB.NET 2, ejecutar

    GenerateProject AjOmar VbNet2Nh

La solución generada

En ambos casos, VB.NET o C Sharp, se generan directorios dentro de Build\AjOmar:

Si vemos el ejemplo C Sharp, queda un archivo de solución en Build\AjOmar\CSharp2Nh\Src, que al abrirlo en el Visual Studio 2005 queda:

Hay varios proyectos de librerías de clases:

  • AjNHibernate: contiene las clases para el manejo de las llamadas al NHibernate, como configuración, factoría y obtención de sesiones.
  • AjOmar.Data: acá están los DAO (Data Access Objects, aunque son clases con métodos estáticos) y el .hbm de mapeo, codificado como recurso embebido en el proyecto.
  • AjOmar.Entities: las entidades del dominio.
  • AjOmar.Services: simplemente una capa de servicio delgado.

Veamos como ejemplo la entidad Company en AjOmar.Entities:

 

/* * Project AjOmar * Example AjOmar for (N)Hibernate * Entity Company * Company Entity * */ using System; namespace AjOmar.Entities { public class Company : Client { // Private Fields private string companyName; private string contactName; // Default Constructor public Company() { } // Factory Methods public static Company Create( string companyname , string contactname ) { Company company; company = new Company(); company.CompanyName = companyname; company.ContactName = contactname; return company; } // Public Properties public string CompanyName { get { return companyName; } set { companyName = value; } } public string ContactName { get { return contactName; } set { contactName = value; } } } }

Gracias al ejemplo inicial que me envió Omar, pude generar un .hbm con subentidades:

 

<?xml version="1.0" encoding="utf-8" ?> <hibernate-mapping xmlns="urn:nhibernate-mapping-2.0"> <class name="AjOmar.Entities.Client, AjOmar.Entities" table="ajom_clients"> <id name="Id" column="Id" type="Int32" unsaved-value="0"> <generator class="native"/> </id> <property column="PhysicalAddress" type="String" name="PhysicalAddress" length="255"/> <property column="ContactEmail" type="String" name="ContactEmail" length="255"/> <property column="RegisterDate" type="DateTime" name="RegisterDate" length="255"/> <property column="Active" type="Boolean" name="Active" length="255"/> <joined-subclass name="AjOmar.Entities.Company, AjOmar.Entities" table="ajom_companies"> <key column="Id" /> <property column="CompanyName" type="String" name="CompanyName" length="255"/> <property column="ContactName" type="String" name="ContactName" length="255"/> </joined-subclass> <joined-subclass name="AjOmar.Entities.User, AjOmar.Entities" table="ajom_users"> <key column="Id" /> <property column="FirstName" type="String" name="FirstName" length="255"/> <property column="LastName" type="String" name="LastName" length="255"/> </joined-subclass> </class> </hibernate-mapping>

Hay un proyecto web AjOmar.WebClient, con una página inicial, un tema, un master page, y un directorio con páginas de navegación y actualización del modelo:

Desde el menú de administración pueden actualizarse los datos:

No es un “qué bruto, qué página”, pero algo funciona… Jeje, lo mío no es el diseño gráfico. 🙂

Noten que en web.config, coloqué la configuración del NHibernate:

 

<nhibernate> <add key="hibernate.connection.provider" value="NHibernate.Connection.DriverConnectionProvider" /> <add key="hibernate.dialect" value="NHibernate.Dialect.MsSql2000Dialect" /> <add key="hibernate.connection.driver_class" value="NHibernate.Driver.SqlClientDriver" /> <add key="hibernate.connection.connection_string" value="server=(local);database=AjOmar;uid=sa;pwd=" /> </nhibernate>

y un HttpModule para manejar la sesión:

<httpModules> <add type="AjNHibernate.SessionHttpModule, AjNHibernate" name="NHSessionModule" /> </httpModules>

Próximos pasos

Quedan para encarar en la próxima versión

  • Utilizar la última versión de NHibernate (con esquema 2.2)
  • Ver de poner los tipos SQL que pedía Omar
  • Probar contra SQL Server 2005
  • Ver de agregar “lazy” en las joined subclasses del mapeo
  • Generar para VB.NET 1.x/CSharp 1.x
  • Generar con conceptos de Domain-Driven Design (capa Presentation+Application+Domain+Infrastructure).
  • Generar código para Java con Hibernate y MySql

Nos leemos!

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

Leave a Reply

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