NHibernate y ASP.NET MVC

NHibernate es la versión de Hibernate (Java) para .NET. Es una herramienta para el mapeo objecto-relacional que ayuda a identificar en nuestro código los atributos de una clase con las columnas de nuestras tablas, por decirlo de una forma simplificada.
El objetivo es que, para el programador, sea posible manejar su base de datos a través de los objetos de .NET, con lo que se consigue una mayor abstracción.
Podemos conseguir más información en la página oficial de la comunidad de usuarios. También tenemos a nuestra disposición el grupo de Google NHibernate-Hispano, donde podrán echarnos una mano con esta librería.

Para poder utilizarla, voy a comentar una serie de pasos a tener en cuenta para su configuración:

  • Descargar la librería de NHibernate.
  • Crear una clase para el manejo de sesión y configuración de NHibernate.
  • Configuración en el archivo web.config.
  • Creación de nuestros objetos de negocio.
  • Creación de los archivos de mapeo.

DESCARGAR LA LIBRERÍA DE NHIBERNATE

En este post, vamos a trabajar con la versión NHibernate-2.1.0.GA. Para descargar la misma podemos hacerlo a través del siguiente enlace.

Como a día de hoy, nos encontramos en la versión ASP.NET MVC 1.0 y la 2.0 sigue estando en fase de desarrolo, vamos a utilizar la 1.0 para crear el ejemplo. Dicho esto, creamos un proyecto MVC (Si tenemos las dos versiones instaladas, se pueden diferenciar perfectamente ya que MVC 2.0 Preview 1 ó 2 tiene un 2 en el nombre de la plantilla).

En mi caso, voy a llamar a mi proyecto MovieManager. Confirmamos la creación del proyecto y lo primero que nos sugiere es crear un proyecto de Test. Aceptamos la sugerencia para poder utilizala más adelante 😀

Llegados a este punto, es necesario añadir una serie de referencias a nuestro proyecto. Descomprimimos el paquete que acabamos de descargar y añadimos las siguientes:

  • NHibernate.dll
  • Iesi.Collections.dll
  • log4net.dll
  • NHibernate.ByteCode.LinFu.dll

Cómo ya expliqué en un post anterior sobre la estructura de un proyecto ASP.NET MVC, tenemos tres partes bien diferenciadas: Modelo, Controlador, Vista(s). En este post, vamos a comenzar por la parte del modelo donde utilizaremos NHibernate.
En primer lugar, voy a crearme rápidamente una base de datos en SQL Server 2008 Express llamada MovieManager con una sola tabla por el momento.

CREAR UNA CLASE PARA EL MANEJO DE SESIÓN Y CONFIGURACIÓN DE NHIBERNATE

Cuando realizamos consultas a base de datos con NHibernate, es necesario controlar la sesión. A través del objeto session tenemos a nuestra disposición métodos como Save, Update, CreateCriteria, etc. Es muy importante manejar correctamente la sesión aunque espero poder hacerlo en algún post más adelante.

using NHibernate;
using NHibernate.Cfg;

namespace MovieManager.Models
{
public sealed class Connection
{
private static ISessionFactory _sessionFactory;
private static Configuration _nhConfig;
private static ISession _session;

public static ISession Session
{
get
{
if (_session == null)
GetCurrentSession();
return _session;
}
}

private static void Init()
{
_nhConfig = new Configuration();
_nhConfig.AddAssembly("MovieManager");
_sessionFactory = _nhConfig.BuildSessionFactory();

}
private static ISessionFactory GetSessionFactory()
{
if (_sessionFactory == null)
Init();
return _sessionFactory;
}

private static void GetCurrentSession()
{
_session = GetSessionFactory().OpenSession();
}
}
}

Actualizado 02/11/2009: Elimino los métodos innecesarios para este post en concreto. Mostraré en otro post diferente cómo sería la manera correcta de manejar la sesión y transacción de NHibernate.

CONFIGURACIÓN DEL ARCHIVO WEB.CONFIG

En el código anterior, teníamos una función Init() que se encargaba de cargar la configuración de NHibernate. Para que esto sea posible es necesario crear una sección en el web.config dónde configuramos todo lo relativo a la base de datos que queremos utilizar.

<section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler,NHibernate" requirePermission="false"/>

Una vez declarada la sección, escribimos la misma con los valores necesarios para conectarnos a la base de datos oportuna:

<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">
<session-factory>
<property name="connection.provider">NHibernate.Connection.DriverConnectionProvider, NHibernate</property>
<property name="connection.connection_string">
Server=localhostsqlexpress;initial catalog=MovieManager;Integrated Security=true
</property>
<property name="dialect">NHibernate.Dialect.MsSql2000Dialect</property>
<property name='proxyfactory.factory_class'>NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu</property>
</session-factory>
</hibernate-configuration>

Actualizado 02/11/009 : Elimino la propiedad current_session_context_class, ya que por el momento no es necesario establecerla.

Existen varios dialectos soportados para poder utilizar distintos tipos de bases de datos. Para más información sobre ello, os facilito el siguiente enlace.

CREACIÓN DE NUESTROS OBJETOS DE NEGOCIO

La base de datos que tengo en mente almacena información sobre peliculas. Como hasta ahora solamente tenemos una tabla llamada Movies en nuestra base de datos, voy a crear la clase en .NET que representa a dicha tabla.

using System;
namespace MovieManager.Models.Objects
{
public class Movie
{
public int Id { get; set; }
public string Name { get; set; }
public string Genre { get; set; }
public string Synopsis { get; set; }
public DateTime Year { get; set; }
}
}


La clase Movie, no contiene ningún método especial ni atributo que tenga relación con NHibernate. Ese rol, lo tiene el archivo de mapeo que será el que relacione cada propiedad de esta clase con la columna de una tabla específica.

CREACIÓN DE LOS ARCHIVOS DE MAPEO

Para crear el archivo de mapeo necesitamos saber, el nombre de la tabla, el nombre de la clase que representará en .NET a nuestra tabla y los campos que queremos recuperar de base de datos.

 

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
<class name="MovieManager.Models.Objects.Movie,MovieManager" table="Movies" lazy="false">
<id name="Id" column="Id" unsaved-value="0">
<generator class="native" />
</id>
<property name="Name" column="Name" />
<property name="Genre" column="Genre"/>
<property name="Synopsis" column="Synopsis" />
<property name="Year" column="Year" />
</class>
</hibernate-mapping>

Hay que tener en cuenta un paso muy importante, a la par que olvidadizo 🙂 , y es lo siguiente: El archivo de mapeo debe tener la extensión .hbm.xml y, además, tenemos que asegurarnos de que el Action Build asignado a estos archivos de mapeo sea Embedded Resource ya que de no ser así la configuración de NHibernate no los tendrá en cuenta.

Con estos pasos, nuestra aplicación estaría lista para funcionar con NHibernate, ocupando la parte del Modelo. En el próximo post me centraré en la parte del controlador y vista para poder solicitar información al modelo y que el usuario pueda obtener a través de la vista los resultados recibidos.

¡Saludos!

13 comentarios en “NHibernate y ASP.NET MVC”

  1. Hola Carlos,

    No, aún no tuve tiempo de echarle un vistazo, aunque ya había oido sobre él. Muchas gracias por el link 🙂

    Tengo taaaaaaaantas cosas que ver 😀

    Gracias por tu comentario, ¡Saludos!

  2. Hola Gisela. Muchas gracias por tan buen post.

    Estaré a la espera de tus otros post de nHibernate.

    Una consulta. ¿Conoces el Entity Framework? ¿Cuales son las ventajas y desventajas del nHibernate en comparación al Entity Framework?

    Saludos

  3. Hola Arturo,

    Muchas gracias por tu comentario 🙂
    En realidad, por motivos de trabajo, he utilizado más NHibernate que Entity Framework, aunque si he podido hacer alguna demo con ello.
    A simple vista te puedo decir que Entity Framework está más integrado en Visual Studio que NHibernate y, este último necesita realizar algunas configuraciones de una forma más manual.
    En cuanto a rendimiento no sabría decirte si es un dato considerable.
    Si te parece, puedo hacer un post con la configuración para EF en este mismo contexto.

    ¡Saludos!

  4. El manejo de la sesión tiene para mi un “smell”.
    Veo “Bind” pero no veo “unbind”, dado que la sessionFactory es privada, nadie incluso desde afuera de esa clase puede hacer unbind. Por otro lado no entiendo el hecho de que al pedirle a esa clase la sesión actual se haga un bind SIEMPRE.
    Si lo que estas haciendo es session-per-request, es decir “session y transaction tienen el mismo ciclo de vida que el request web”, el bind debería ser realizado en el beginrequest (podes hacerlo directamente en Global.Asax), y el unbind en EndRequest. Luego inyectar ISessionFactory en los repositorios/daos que es lo que hacemos la mayoría, y a él solicitarle GetCurrentSession.
    Si no estas haciendo “session-per-request” (MUY RECOMENDADO), no te hace falta hacer nada con el context (ni si quiera configuralo en el config).

  5. Buenos días José 🙂

    Mi idea era dejar preparada más o menos la clase Connection.cs para usar session-per-request utilizando Global.asax y, obvio, HttpModule… Pero no me llega el tiempo para hacer un post tan largo 🙁

    Por otro lado, también quería hacer session-per-request con Action Filter, como comencé en el anterior Blog pero utilizando un mismo atributo para la sesión y la transacción.

    Entiendo que, una vez implementada la clase que hereda IHttpModule, debo bindear al inicio y hacer el unbind al final, eliminando el Bind que se encuentra dentro del método GetCurrentSession();

    Cuando tenga configurada la aplicación para hacer session-per-request  el atributo session factory debería ubicarse en el Global.asax para tener acceso desde toda la app. ¿Puede ser?

    Quizás lo dejé un toke a medias y podía haberlo simplificado más… Intentaré revisarlo en cuanto pueda y elimino las cosas innecesarias, para que se entienda qué es lo necesario en este caso en concreto.

    Gracias por tu comentario

    ¡Saludos!

  6. Ufff creo que ya está ;D

    Por el momento, como quiero seguir escribiendo post sobre NHibernate, MVC, etc, no me interesa hacerlo todo perfecto ni mucho menos sino introducir mejoras y que el lector sepa por qué se introducen.
    Gracias a José Romaniello, del que siempre aprendo algo :D, intento mejorar todo lo que hago en cuanto a NH se refiere.
    No soy ninguna experta en esta librería y hay muchas cosas con las que no he tenido que pelearme y por lo tanto aprender de ellas.
    Quiero intentar hacer las cosas lo más simple posible para luego poder explicar las ventajas que supone modificar el código de una forma u otra 🙂

    ¡Saludos!

  7. Gisela, me agrada como expresas tus ideas. Este artículo es un buen inicio para aquellos que se aventuran a usar NH. Ojalá lo puedas complementar.

    Un saludo!!

  8. Saludos, tengo el siguiente problema:
    Description: An error occurred during the processing of a configuration file required to service this request. Please review the specific error details below and modify your configuration file appropriately.

    Parser Error Message: Unrecognized configuration section section.

    Source Error:

    Line 76:
    Line 77:
    Line 78:

    Line 79:
    Line 80:

  9. Hola Fausto,

    Perdona por la espera,

    Parece que no está reconociendo correctamente la nueva sección de la configuración de NHibernate.

    Comprueba que está correctamente definida dentro de <configSections> Sin que esté ubicada dentro de ningún  </sectionGroup>. Me explico:

    <configuration>
    <configSections>
    <sectionGroup ...

    </sectionGroup>
    <section name="hibernate-configuration" type="NHibernate.Cfg.ConfigurationSectionHandler,NHibernate" requirePermission="false"/>
    </configSections>

    Espero que con esto te sirva 🙂

    ¡Saludos!

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *