Anda di halaman 1dari 4

Tutorial de NHibernate - Primeros pasos

1 de 4

http://darioquintana.com.ar/articles/tutorial-de-nhibernate-primeros-pasos

darioquintana.com.ar

Tutorial de NHibernate - Primeros pasos


Ultima revisin: 4 de junio 2007
NHibernate es un framework de O/RM (Object/Relational Mapping), un port de Hibernate de Java, que tiene como funcin principal mapear los objetos desde una aplicacin .Net
a una base de datos Relacional. Primero, hablemos de como NH (NHibernate) realiza su funcionamiento bsico.

Cdigo de ejemplo
En el siguiente ejemplo ser solamente puntapi inicial para introducirnos en este framework de persistencia, si bien contiene algunos consejos como buenas prcticas pero no es lo
que persigue, por esta razn los ejemplos sern sencillos. De hecho, el modelo posee una clara correspondencia de 1 objeto => 1 tabla, lo cual en la realidad no debe buscarse, ya
que los modelos de dominios y de datos buscan resolver problemas diferentes, y si estamos en presencia de esto, es muy probable que no estemos explotando todo el potencial de
ambos modelos, y por sobre todo de esta herramienta. NHibernate nos da la libertad de realizar un modelo de dominio, y despus mapearlo a un modelo de tablas, y viceversa. El
cdigo de ejemplo lo pueden descargar aqu Dario.NH01.zip

Modelo de Dominio
El modelo de dominio con el cual trabajaremos ser el siguiente:

Modelo relacional
El modelo de datos estar representado por estas tres relaciones (tablas):

Mappings Files Archivos de Mapeo:


NH para poder conocer la correspondencia que existe entre los objetos y las tablas lo hace por medio de la configuracin de mapeo. Esta configuracin se puede hacer de forma
programtica o bien, la ms utilizada, que consiste en archivos de mapeo XML (mapping files). Estos archivos poseen la informacin necesaria para poder saber en qu tabla/s se
tiene/n que guardar cada objeto en que tabla tengo que buscar para obtener un objeto. Los nombres de los archivos terminan con el sufijo .hbm.xml. Las extensiones de estos
archivos xml es .hbm.xml. Por ejemplo Factura.hbm.xml, LineaFactura.hbm.xml, Producto.hbm.xml.

Archivo de Mapeo de la clase Factura (Factura.hbm.xml):


<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Dario.NH01" namespace="Dario.NH01.Entidades">
<class name="Factura">
<id name="Id" column ="IdFactura" type="int" unsaved-value="0">
<generator class="identity"/>
</id>

20/04/2009 19:23

Tutorial de NHibernate - Primeros pasos

2 de 4

http://darioquintana.com.ar/articles/tutorial-de-nhibernate-primeros-pasos

darioquintana.com.ar
<property name="Fecha" type="DateTime" not-null="true"/>
<bag name="Lineas" cascade="all-delete-orphan">
<key column="IdFactura"/>
<one-to-many class="LineaFactura"/>
</bag>
</class>
</hibernate-mapping>

Veamos los atributos del archivo. Al comienzo del archivo estamos indicando el nombre del assembly: Dario.NH01, donde van a estar ubicadas las clases. Luego el namespace de
dicha clase. Luego comenzamos a tratar las caractersticas de la clase que queremos mapear con el atributo class, en este caso Factura. Dentro de los tags <class
name="Factura"...> ... </class> vamos a indicar todas las configuraciones de dicha clase. Un atributo que no hemos marcado en el mapping pero que viene activado por
defecto y vale la pena explicarlo es lazy="true". Con esto activamos la carga perezosa, lazy load, de modo que las colecciones no se cargarn hasta que sean utilizadas. Este
funcionamiento se logra mediante un proxy y NH se encarga de manejarlo, para nosotros es transparente (por ahora).
Con el tag <id> vamos a indicarle a NH qu property ser mapear con la clave primaria de la tabla, en este caso la property Id se va a corresponder con la columna IdFactura,
ser de tipo int y para indicar que un objeto se considera como nuevo y no como que ya existe en la base, pondremos el atributo unsaved-value="0". Tambien hemos asignado al
generator el valor identity, con esto le decimos NH que se encargue de generar los valores de la primary key. Si hubiramos querido asignarles nosotros el valor, deberamos
reemplazar por el valor assigned. Luego vamos a decirle que la propiedad Fecha, tiene que corresponderse con la columna Fecha, esto es debido que no hemos indicado el nombre
de la columna con el atributo column, y que va a ser de tipo DateTime. Y con esto ya tenemos suficiente como realizar un ABM (Alta/Baja/Modificacin) de la entidad Factura.
Pero para hacer un poco ms interesante esto, agreguemos la relacin 1:N con la clase LineaFactura. Para esto vamos a utilizar el atributo <bag>. Indicamos que el nombre de la
coleccin se llamar Lineas, y como es bag, esta coleccin podr tener elementos repetidos. Para esto utilizamos una coleccin del tipo IList<LineaFactura>. Cabe destacar que
podemos utilizar otro tipo de colecciones que se encuentran en la librera Iesi.Collections.dll.

Archivo de Mapeo de la clase LineaFactura (LineaFactura.hbm.xml):


<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="Dario.NH01" namespace="Dario.NH01.Entidades">
<class name="LineaFactura">
<id name="Id" column ="IdLineaFactura" type="int" unsaved-value="0">
<generator class="identity"/>
</id>
<property name="Cantidad" type="int" />
<property name="Precio" type ="Decimal"/>
<many-to-one name="Factura" column="IdFactura" />
<many-to-one name="Producto" column="IdProducto" />
</class>
</hibernate-mapping>

Algo a notar en este archivo es la declaracin de la relacin many-to-one para la propiedad Factura y tambin para Producto.

Archivos de mapeo como recursos embebidos


Es una prctica muy comn y recomendable el incluir los archivos de mapeo como recursos embebidos dentro de un assembly. Cualquier IDE de desarrollo moderna -Sharp
Develop, Visual Studio Monodevelop-, nos permiten configurar las propiedades de los archivos y que accin se debe tomar con ellos, dicha opcin se llama Action Build / Accin
de Construccin y entonces debemos configurarla como: Embedded Resource/Recurso embebido. Si olvidamos hacer esto con los archivos de mapeo, es posible que no tengamos
ningn error en algunos casos, pero no funcionar correctamente.

Preparando las clases


Mtodos y Propiedades
Al estar trabajando con clases con lazy="true", que es el valor por defecto, todos los mtodos y propiedades deben ser declarados como virtual. De este modo NH puede crear
un proxy de nuestras entidades, esto es transparente para nosotros.

Sobrescribiendo Equals y GetHashCode


Para poder trabajar correctamente con colecciones debemos sobrescribir estos mtodos. Sino sobrescribimos el Equals al hacer una operacin como
de la misma linea de factura, debido a que la comparacin se est haciendo por la posiciones de

lineaFactura1.Equals(lineaFactura2) podra devolver false an tratndose


memoria. Cuando sobrescribimos Equals por ejemplo de esta manera:

public override bool Equals(object obj)


{
if (this == obj) return true;
LineaFactura lineaFactura = obj as LineaFactura;
if (lineaFactura == null) return false;
return id == lineaFactura.id && Equals(factura, lineaFactura.factura);
}

De este modo nos aseguramos de que 2 objetos son iguales si son iguales sus propiedades Id y Factura.
Ya hemos sobrescrito el Equals, ahora debemos hacer lo mismo con GetHashCode, debido a que 2 objetos iguales deben tener un mismo nmero de hash (y 2 objetos distintos
pueden o no tener el mismo nmero de hash). El nmero hash no representa un id, no tiene que ser nico.
Una posible implementacin podra ser:
public override int GetHashCode()
{
return id + 29*factura.GetHashCode();
}

Con este mtodo nos aseguramos que 2 lneas factura devuelvan el mismo nmero al ser iguales. Al trabajar con nmeros primos obtenemos buenas funciones hash. Lo importante
aqu es hacer bien la funcin, la optimizacin de esta funcin queda fuera del alcance del tutorial.

Implementando IEquatable<T>
Todas las entidades implementan IEquatable<T>, esto no es necesario para trabajar con NHibernate, solamente es una manera de hacer que las comparaciones por medio de
Equals se realicen de forma tipada.

ISessionFactory e ISession
Una sesin es un marco de trabajo en el cual NH establece una conversacin entre la aplicacin y el motor de base de datos relacional. Para construir una sesin, representado por
ISession alguien que nos provea la sesin, para esto necesitamos de: ISessionFactory. El ISessionFactory se encarga crear sesiones en nuestra aplicacin. En un momento, la

20/04/2009 19:23

Tutorial de NHibernate - Primeros pasos

3 de 4

http://darioquintana.com.ar/articles/tutorial-de-nhibernate-primeros-pasos

darioquintana.com.ar
aplicacin puede tener 1 o ms sesiones abiertas. Cada sesin representa un 1er. nivel de cach, los objetos que son trados desde la base, o son guardados desde la aplicacin se

encuentran en la cache de primer nivel. Si se solicita un objeto a la base, primero se busca en la cach, si se encuentra ah el objeto, se lo devuelve a la aplicacin sin solicitarlo al
motor relacional. Sino se encuentra en la cach, se realiza la consulta a la base.
Por lo general debemos tener un ISessionFactory por aplicacin, sera necesario tener ms de uno en el caso de que estemos trabajando con ms de una base de datos a la vez.

Configuracin del ISessionFactory de la aplicacin


Para configurar el ISessionFactory, es decir, para decirle con qu motor de base de datos vamos a trabajar, la cadena de conexin (connection string), el driver que utilizaremos
entre otras cosas, como toda configuracin en NH, se puede realizar de manera programtica (por cdigo) o mediante archivos de configuracin XML, y dentro de esta ltima
podemos hacerlo mediando el App.config o mediante el hibernate.cfg.xml. Utilizaremos la ltima en este caso:
<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2" >
<session-factory name="NH01">
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>
<property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>
<property name="dialect">NHibernate.Dialect.MsSql2005Dialect</property>
<property name="connection.connection_string">Data Source=localhost\SQLEXPRESS;Initial Catalog=NH01;Integrated Security=True</property
<property name="show_sql">true</property>
<mapping assembly="Dario.NH01" />
</session-factory>
</hibernate-configuration>

En esta configuracin hemos incluido el nombre del assembly donde se encontrarn embebidos los archivos de mapeo, en este caso el assembly es: Dario.NH01.
El cdigo necesario para configurar NH al comienzo de la aplicacin es:
Configuration cfg = new Configuration();
cfg.Configure("hibernate.cfg.xml");
ISessionFactory sesiones = cfg.BuildSessionFactory();
ISession sesion = sesiones.OpenSession();

Primeramente debemos crear un objeto del tipo Configuration, configurarlo mediante Configure("hibernate.cfg.xml") y que se encargue de crear el ISessionFactory, por
medio del mtodo BuildSessionFactory(). Una vez que creamos el objeto sesiones del tipo ISessionFactory, ya podemos comenzar a crear objetos ISession. En este caso
trabajaremos con una sola sesin en la aplicacin: sesion.
Es una buena prctica realizar un singleton del objeto ISessionFactory debido a que es un proceso costoso para la aplicacin, en otras palabras, la ejecucin de
se debe hacer una vez durante la ejecucin.

BuildSessionFactory

Creamos Productos, Facturas y Lneas


Ahora comenzamos con el cdigo de ejemplo, primero creamos Productos y los guardamos:
Producto prod1 = new Producto("Leche Entera", "Lacteos");
Producto prod2 = new Producto("Lavandina", "Limpieza");
Producto prod3 = new Producto("Vasos", "Bazar");
sesion.Save(prod1);
sesion.Save(prod2);
sesion.Save(prod3);

Creamos 3 productos y los guardamos en la sesin sesion mediante el mtodo Save. Una vez hecho esto podemos continuar con la creacin de la Factura y sus LineaFactura.
Factura factura = new Factura(DateTime.Now);
factura.Lineas.Add(new LineaFactura(factura, prod1, 2.25m, 5));
factura.Lineas.Add(new LineaFactura(factura, prod2, 3.5m, 1));
factura.Lineas.Add(new LineaFactura(factura, prod3, 5.4m, 10));
sesion.Save(factura);
sesion.Flush();
sesion.Close();

Una vez creada factura, podemos realizar un Save . Notse aqu que hemos guardado la factura, y las lneas tambin se guardaron. Esto es debido a que en el mapping de Factura
hemos configurado el Agregado/Actualizacin/Borrado en cascada mediante la siguiente lnea cascade="all-delete-orphan". Despus de realizar todos las inserciones,
procedemos a realizar Flush() para que se ejecuten las sentencias SQL propiamente dichas contra el servidor, en ese momento se guardan todos nuestros objetos, antes de esto los
objetos permanecan en el objeto sesion (en la cache de 1er. nivel).
Luego de que hemos usado la sesin, liberamos los recursos realizando un Close().

Intellisense para los archivos de mapeo en Visual Studio


Los archivos de mapeo de este ejemplo fueron escritos sin ayuda de una herramienta de generacin de cdigo. Solamente con ayuda del Intellisense de Visual Studio en los archivos
XML. Para tener esta funcionalidad se deben copiar los archivos nhibernate-mapping-2.2.xsd y nhibernate-configuration-2.2.xsd al directorio C:\Archivos de
programa\Microsoft Visual Studio 8\Xml\Schemas donde se tiene instalado el Visual Studio.

Conclusin
En este tutorial vimos nuestros primeros pasos con NHibernate mediante una simple aplicacin de Consola. Se mostr como crear objetos y como persistirlos, inclusive como
persistir una relacin en cascada de padres e hijos (Factura - LineaFactura).

Consultas y comentarios
NHibernate Hispano - Grupo de Usuario de NHibernate en Espaol

20/04/2009 19:23

Tutorial de NHibernate - Primeros pasos

4 de 4

http://darioquintana.com.ar/articles/tutorial-de-nhibernate-primeros-pasos

darioquintana.com.ar

20/04/2009 19:23

Anda mungkin juga menyukai