Está en la página 1de 5

NHibernate, ejemplo prctico

Para abrir el blog no eleg mejor tema que el grandioso framework de persistencia, de
cual puedo estar hablando sino es NHibernate.
La idea principal de esta publicacin ser ni ms ni menos que proporcionar un ejemplo
integral de varias caractersticas que mucha falta hacen y que tanto cuesta aprender al
comenzar con esta herramienta.
Este artculo no tiene intencin de ser detallista ni explicar puntualmente cada aspecto
implementado, para ello podr encontrar artculos mas destacados como por ejemplo el
excelente articulo publicado en el Blog de Dario Quintana.
La idea final es simplemente proporcionar un ejemplo que permita ver varias
caractersticas funcionando juntas.
Aspectos implementados
Entre las caractersticas implementadas encontraran los siguientes puntos:

Modelo completamente tipado


Relaciones many-to-one, one-to-many y many-to-many
Persistencia de enumerados
Persistencia de campos nText (type="StringClob")
Herencia table per class hierarchy <subclass>, table per subclass <joinedsubclass>
Herencia table per class hierarchy <subclass>, utilizando una formula en el
<discriminator>.
Consultas hql entre relaciones many-to-many

Descargar Ejemplo
Diagramas del Dominio

Diagrama del dominio de la Institucion

Diagrama del dominio de reserva de libros

Diagramas de persistencia en SQL Server 2005

Diagrama de Base de Datos de la Institucion

Diagrama de Base de Datos de las Reservas de libros


Persistencia de Enumerados
Un punto mas que importante para brinda consistencia al modelo, es la utilizacin de
enumerados en al definicin del dominio de la aplicacin.
En la clase ClaseEntity, se observara un atributo de nombre FormaPago definido como un
enumerado, por supuesto en la definicion de su mapper (Clase.hbm.xml) encontraran la
definicin de de la propiedad
<property
type="NHib.Infrastructure.GenericEnumMapper`1[[NHib.Domain.Entities.enumFormaPago
, NHib.Domain]], NHib.Infrastructure" name="FormaPago" column="FormaPago" />
Se observa claramente la utilizacin de un mapper de enumerado (el cual esta alojado
dentro del NHib.Infrastructure), el cual permitir recuperar el nmero asignado al tem
del enumerado asignado.
Persistencia de campos nText
Un tema interesante para probar es la persistencia de atributos espaciales, como es el
caso de comentarios, los cuales deben contener texto que escapa a un simple
descripcin. Es en estos casos que se utilizara en nText, existiendo en NHibernate una
forma especial de definir este tipo de mapeo.
En la clase LibroEntity, es justamente donde se hace uso de este, en el atributo
Comentarios definido en el mapper como:
<property column="Comentario" type="StringClob" name="Comentario" />
Es en la clase de test TestLibro.cs -> LargoComentarios(), donde se realiza una prueba de
su correcta persistencia, comprobando que no se trunca el valor del atributo
Herencia

En la aplicacin encontraran tres tipos de herencia implementada, utilizando:


Tabla para todas las clases
Este primer tipo de implementacin lo ubicaran en la entidad LibroEntity, en esta se
remarca la definicion de los atributos discriminator-value el cual toma un valor numerico
cuyo tipo es definido en el tag <discriminator>
Se aclara que el tipo de dato por defecto definido es del tipo de datos string, esto a
simple vista pareciera no tener mayor implicancia, pero al momento de utilizar un
<discriminator> con valores numricos, todas las clases debern tener definido un
discriminator-value, aunque la clase principal no sea utilizada.
En el ejemplo la defincin del tag <class>, al estar utilizando la interface ILibroEntity,
debe definir un discriminator-value, con un valor que no es utilizado por el modelo como
diferenciador en la herencia de clases, esto debe hace con el simple objetivo de evitar
un error de tipos de datos.
Tabla para cada subclase
La implementacin se podr observar en la clase ReservaEntity, a diferencia del ejemplo
anterior que utiliza una sola clase, no existe el discriminator-value, y es por medio de la
relacion uno a uno de las tablas que se mapean como se obtiene el tipo de objeto.
En este caso se hara uso de un tag de mapeo: <joined-subclass>, la cual definir cual es
el atributo relacin entre las tablas, siendo esta la razn de utilizar <key column="" />
Herencia utilizando formulas en el discriminator
Esta ser utilizada en los casos en donde se pretenda generalizar entidades que pueden
ser agrupadas desde otro nivel de abstraccin que requiere el modelo analizado.
En el ejemplo sucedi con los convenios, (definido en la entidad ConvenioEntity) el cual
describe la existencia de varios tipos de talleres y excursiones, que se pueden asociar a
una institucin.
Pero el modelo solo necesitaba diferenciar entre convenios del tipo taller y excursin,
para esto necesita agrupar distintos valores en un discriminator.
Adems para aumentar la complejidad el atributo esta definido con un carcter mientras
que el mapeo har uso de un valor numrico.
Es por medio del atributo formula que se transformara el valor del discriminator de una
valor del tipo carcter a uno numerico.
Se debe aclarar que este tipo de definiciones presentan un inconveniente, solo podrn
recuperarse los distintos tipos de subclases definidas, pero no podrn persistirse, ya que
es imposible por medio de la definicin de la formula saber que atributo de tipo
especificar, esto deber realizarse implcitamente en la definicin de la clase a persistir.
Es por esta razn que se notara la definicin de un enumerado dentro de las subclases
que permita diferenciar las distintas clases concretas de Convenios. La redefinicin del
constructor permite forzar la especificacion al momento de crear una nueva subtipo de
Convenio.
El framework necesita la especificacin de un constructor sin parmetros, pero para
evitar su utilizacin es que se define como protected. Al igual que la definicin del
atributo Tipo (tambin protected) que permitir ser utilizado solamente por el
mapper, permitiendo especificar el tipo concreto a persistir.
Ademas se debe entender que por tratarse de un campo del tipo char, se realiza por
medio del case la asignacin del valor correcto, si hubiera sido numrico se podra
haber persistido el enumerado directamente como el caso visto en a persistencia de
enumerados.

Consultas hql entre many-to-many


Si bien la definicin del mapeo de la navegacin entre entidades resulta de suma
utilidad, hay ocasiones en donde se requiere obtener algn tipo de filtro aplicado al otro
extremo de la relacin, es en este punto donde se har uso de las consultas HQL, y en
ellas el operador JOIN.
Para visualizar un ejemplo de su implementacin se podrn visitar varios puntos donde
fueron utilizados, destacando:

ProfesorRepository -> GetAlumnos(): Implementa un join en donde se recorren dos


relaciones muchos a muchos. Esta podra ser testeada desde TestProfesores ->
RecuperoAlumnos()
AlumnoRepository -> GetByClase(): Define varias sobrecargas con diferente filtros
que son aplicados a un join.

Eliminar en cascada
Como es de suponer esta facilidad de actualizar la cascada de elemetos relacionados es
de muchisima importancia, pero durante la utilizacin de la navegacin entre entidades
me encontre con un pequeo detalle que quera remarcar.
Se trata de la utilizacin de la propiedad inverse="true", esta es de suma importancia
cuando se esta utilizando navegacin bidireccional.
De no especificarse esta propiedad al momento de producirse, por ejemplo, la
eliminacion de un objeto padre, sus hijos seran actualizados y al no encontrase la
entidad superior generar una exception que indicara la imposibilidad de insertar null en
el campo de la tabla.
Esto podria resolverse facilmente marcando el campo de relacin para que permita null
en su contenido, pero no todos los tipos de realaciones en el modelo pueden hacer esto.
Un ejemplo del uso de esta propiedad podra encontrase en el achivo de mapeo de la
entidad Institucion (Institucion.hbm.xml), y la prueba de la eliminacion en cascada se
encuantra en el test: TestInstituciones -> EliminoInstitucion()
Nota: Si quieren probar como funciona esta propiedad eliminenla del archivo de mapeo
Institucion.hbm.xml, de la relacin con el Alumno por ejemplo, e intenten correr el test:
TestInstituciones -> EliminoInstitucion(), para ver los resultados.
Tambien podran marcar el campos "Institucion" de la tabla "Alumnos", observarn como
se soluciona el problema.
Implementacin
En la aplicacin encontraran que esta formada por varias capas entre ellas la de
Aplicacion y Presentacin, pero estas no estn implementadas, pues no era necesario
para el objetivo de aprender NHibernate, simplemente con la utilizacin del proyecto de
Test se pudo comprobar el correcto funcionamiento del framewok de persistencia.
Se debe remarcar que el dominio debe ser tomado algo inventado, no perteneciante a un
dominio existente, pensado simplemente para lograr el objetivo principal de verificar la
funcionalidad de NHibernate.
Si bien el cdigo es sumamente til con tan solo visualizar el cdigo de los test, asi como
tambin el de los mapper, es posible ejecutarlo si se conecta apropiadamente a una base
de datos. Para ellos, como en la mayora de las aplicaciones, simplemente se debe
modificar el app.config del proyecto de pruebas, apuntandolo a la DB que corresponda.
Para crear la estructura de la base de datos se encontrar un proyecto con los script de
creacion de la estructura, o en caso contrario podran hacer uso de los archivos .mdf y
.ldf de la base de datos, adjuntandolos por medio de la opciones de attach del SQL
Server 2005.
Para la ejecucin de los test hice uso de UnitRun, de esta forma poda ejecutarlos uno a
uno en modo debug e ir analizando como se comporta cada uno.

Conclusin
Espero antes que nada haber aportado un granito mas de arena a la investigacin de este
potentsimo framework, apuntando principalmente aspectos un poco mas avanzados de
los cuales es complicado encontrar ejemplo cerrados que los integre.
Quedan varios puntos todava por probar, como ser el mapeo a store procedure,
paginado, etc
Espero les sea de utilidad y cualquier duda, modificacin o error que encuentren sern
bienvenidos.

También podría gustarte