EntityFramework 4.3.0 Released

Recientemente salio a la luz la versión release de Entity Framework 4.3.0 y en la que ya podemos disfrutar de muchas características que seguramente estarán disponibles en la versión 5.0 que viene en camino.

Entre las principales características que podemos encontrar en versión están:

  • New Code First Migrations Feature: esta es una de las principales características de la nueva versión de EF y nos permite ir “migrando” nuestra base de datos creada con Code First a media que el modelo va cambiando. Esto quiere decir que, entre otras cosas, podemos recuperar una instancia determinada de la base de datos entre las distintas versiones (migraciones) que hayamos generado. En un próximo post vamos a ver como trabajar con esta nueva característica.
  • Removal of EdmMetadata table: como ya hemos visto, con Code First podemos crear la base de datos simplemente ejecutando la app. A la creación se le suman todas las ventajas del esquema de generación que forma parte de Migrations.
  • Data Annotations on non-public properties: por defecto Code First no incluye las propiedades protected, private o internal.  Si utilizábamos estos modificadores por medio de otras API, los Data Anottations en dichas propiedades eran ignoradas. En esta nueva versión se ha modificado esta situación por lo que las Data Anottations en esos casos serán procesadas.
  • More configuration file settings: ahora es posible definir muchas más caracteristicas sobre Code First en nuestro archivo de configuración. Todos los detalles aquí.

Instalación desde Nuget:

Instalando EF desde la consola de Nuget

Instalando EF desde la consola de Nuget

Más info sobré la instalación: http://nuget.org/packages/entityframework

Algunos enlaces interesantes sobre el tema:

Anuncios

Entity Framework 4.1 CF y Lazy Load

Para finalizar esta serie de post sobre Entity Framework 4.1 CF, vamos a hablar de una nueva caracteristica: soporte de Lazy Load (Carga Diferida).

Comencemos con una definición general de Lazy Load para que nos demos una mejor idea de que estamos hablando:

El Lazy Loading es un patron de diseño util y simple que se basa en ir cargando los distintos componentes de una clase cuando los vamos usando.

Ahora vamos a ver como trabaja este patrón de diseño dentro del framework EF CF 4.1.

En la definición anterior explica que Lazy Loading tiene como finalidad ir cargando los distintos componentes de una clase a medida que lo vamos usando. Esos componentes en EF se representan por medio de las llamadas propiedades de navegación, las cuales nos proporcionan una forma de navegar de una asociación o relación entre dos tipos de entidades, retornando una referencia a un objeto (si la relación es de cero a uno o uno a uno) o una colección (si la relación es de uno a muchos).

En nuestro ejemplo las propiedades de navegación son: Eventos que pertenece a la clase Agenda y Agenda que pertenece a la clase Evento:

1:     public class Agenda
2:     {
3:         public int AgendaId { get ; set ; }
4:         public string Propietario { get ; set ; }
5:         public DateTime FechaCreacion { get ; set ; }
6:
7:         public virtual ICollection <Evento> Eventos { get ; set ; }
8:     }
1:     public class Evento
2:     {
3:         public int EventoId { get ; set ; }
4:         public int AgendaID { get ; set ; }
5:         public DateTime Fecha { get ; set ; }
6:         public string Comentario { get ; set ; }
7:
8:         public virtual Agenda Agenda { get ; set ; }
9:     }

Notece que por convención dichas propiedades son marcadas como virtual (si no las marcamos de esta forma, no podremos aprovechar las ventajas de LazyLoad).

Antes de escribir nuestra primer linea de código, quiero comentarles que Lazy Loading en EF 4 viene habilitada por default. Esto no es del todo apropiado, sobre todo cuando el volumen de datos es demasiado grande o en el caso de que solo quiera recuperar, por ejemplo, un listado de agendas, donde no me interesa conocer todos sus eventos asociados. Para evitar esto, vamos a decirle al DbContext que por defecto esta característica – LazyLoadingEnabled – venga des-habilitada. Entonces modificamos el constructor de nuestro DatosContext:

1: public class DatosContext : DbContext
2: {
3:     public DbSet<Agenda> Agendas { get; set; }
4:     public DbSet<Evento> Eventos { get; set; }
5:
6:     public DatosContext() : base("name=DatosContext") 
7:     {
8:         this.Configuration.LazyLoadingEnabled = false; 
9:     }
10: }

Ahora sí, ya tenemos nuestro entorno listo, comencemos!

Lo primero que debemos hacer es crear y grabar una agenda y luego asignarle un par de eventos (de esta forma podremos visualizar mejor los ejemplos). Una forma simple de realizar esto es sobre-escribir el método Seed() de la clase DatosInitializer tal como lo explicamos en el primer post de esta serie.

Ya conocemos la forma en que se relacionan nuestras entidades, por lo tanto vamos a hacer uso del método Include() que nos proporciona la clase DbQuery. También podemos hacer uso de la extensión Include() provisto por DbExtensions (para este caso recordemos importar System.Data.Entity).

Include() es el método que nos permite obtener de una consulta el set completo de datos de una entidad y de todas sus relaciones.

Generalmente para recuperar la lista de alguna entidad (en nuestro caso de agendas) escribimos la siguiente consulta:

1: public ActionResult Index()
2: {
3:     var agendas = datos.Agendas.ToList();
4:
5:     return View(agendas);
6: }

Sin embargo, esto no nos recupera la lista de eventos asociados a cada agenda (siempre y cuando hayamos desactivado la característica de Lazy Loading). Inspeccionando la primer agenda de la lista podemos afirmar esto:

Inspeccionando objetos obtenidos con EF4.1 sin LazyLoad

Inspeccionando objetos obtenidos con EF4.1 sin LazyLoad

Para poder recuperar la agenda y sus eventos asociados debemos hacer uso del método Include() donde le pasaremos como parametro la propiedad de navegación de la cual queremos obtener los datos:

1: public ActionResult Index()
2: {
3:     var agendas = datos.Agendas.Include("Eventos").ToList();
4:
5:     return View(agendas);
6: }

Ahora vemos los mismos objetos obtenidos con LazyLoad:

Inspeccionando objetos obtenidos con EF4.1 con LazyLoad

Inspeccionando objetos obtenidos con EF4.1 con LazyLoad

Como observamos, se han recuperado también los Eventos de la agenda.

Para finalizar veamos algunos ejemplos más de lo que podemos hacer con EF y Lazy Load:

1:// Recupero todas las relaciones entre agenda y eventos utilizando DbQuery.
2:// La asociación se especifica por medio de un string.
3:var ag = datos.Agendas.Include("Eventos").ToList();
4:
5:// Recupero todas las relaciones entre agenda y eventos utilizando DbExtensions
6:// La asociación se especifica por medio de una expresion lambda.
7:var ae = datos.Agendas.Include(e => e.Eventos).ToList();
8:
9:// Recupero una agenda creada en el día de hoy y sus eventos.
10:var a1 = datos.Agendas
11:          .Where(a => a.FechaCreacion == DateTime .Now)
12:          .Include(e => e.Eventos)
13:          .FirstOrDefault();

Espero que le haya sido de utilidad.

Introducción Entity Framework 4.1 Code Firts

La versión 3.5 SP1 del framework .NET nos proveia de una biblioteca ORM llamada Entity Framework. Esta primera versión recibió varias criticas por parte de los desarrolladores, las cuales por suerte fueron escuchadas por el equipo de .NET. Es por este motivo que junto a la salida de .NET 4 apareció una versión mejorada llamada Entity Framework 4.1.

Entre las mejoras que se incluyen en esta nueva versión se encuentran: el manejo de clases POCO, soporte para Lazy Load, mejor calidad en las querys SQL generadas, mayor compatibilidad con Linq entre otras más.

En este post vamos a trabajar con una nueva caracteristica de EF llamada Code Firts (cuya traducción valida prodía ser “Partiendo del código“) y cuyo punto fuerte es que partiendo de nuestras clases del dominio ya podemos crear nuestro modelo ORM. Todo esto sin preocuparnos por la creación de la base de datos, el mapeo entre las entidades y la DB, los archivos XML o editores y todas las configuraciones afines.

Pero vayamos por parte, antes de comenzar con un ejemplo, vamos a crear un proyecto ASP.NET MVC 3 y agregar las referencias a esta librería. Para poder trabajar con EF 4.1 Code First antes vamos a tener que instalar el componente EFCodeFirst y podemos hacerlo de una manera muy sencilla utilizando Nuget (en la pestaña online\all buscamos dicho componente e instalamos).

Instalando EF4.1 desde Nuget

Instalando EF4.1 desde Nuget

Finalizada nuestra instalación se nos abrirá un archivo ReadMe con algunos comentarios sobre el producto y se habrán agregado a la solución los assemblies correspondientes.

El segundo paso sera crear las entidades del modelo, en este ejemplo vamos a trabajar con dos entidades muy simples, la primera representara una agenda y la segunda eventos de la misma. Estas clases a crear son objetos simples denominados POCO en el ambiente .NET (es importante que estas clases POCO respeten algunas convenciones que no son para nada complejas y que nos permitirán trabajar con EF).

Es el turno de definir las clases que compondran nuestro modelo:

1:     public class Agenda
2:     {
3:         public int AgendaId { get ; set ; }
4:         public string Propietario { get ; set ; }
5:         public DateTime FechaCreacion { get ; set ; }
6:
7:         public virtual ICollection <Evento> Eventos { get ; set ; }
8:     }

1:     public class Evento
2:     {
3:         public int EventoId { get ; set ; }
4:         public int AgendaID { get ; set ; }
5:         public DateTime Fecha { get ; set ; }
6:         public string Comentario { get ; set ; }
7:
8:         public virtual Agenda Agenda { get ; set ; }
9:     }

Algo interesante a comentar de estas entidades es que las propiedades definidas como virtual corresponden a propiedades de navegación, y son aquellas que se pueden cargar en “diferido” (en otro post vamos a ver de que se trata esto).

El segundo paso será crear un contexto que nos permita realizar operaciones CRUD sobre nuestras instancias de Agenda y Evento. Para esto vamos a crear una clase llamada DatosContext que derive de DbContext y que contendra dos propiedades publicas (una por cada entidad del modelo que hemos creado) que seran del tipo DbSet<T>:

1: using System.Data.Entity;
2:
3: namespace MvcAndEF.Models
4: {
5:     public class DatosConext : DbContext
6:     {
7:         public DbSet<Agenda> Agendas { get ; set ; }
8:         public DbSet<Evento> Eventos { get ; set ; }
9:     }
10: }

Como ya se habran dado cuenta, estas librerias pertenecen a System.Data.Entity y son provistas por EF4.1. Las clases DbContext y DbSet nos permitiran realizar las operaciones relacionadas con el acceso a los datos.

A pesar de todo esto aún no hemos creamos la base de datos y mucho menos un mapeo con la misma, tampoco hemos utilizamos diseñadores y mucho menos realizamos configuraciones. Sin embargo ya estamos listo para trabajar! 🙂

Cómo es posible esto?… la respuesta es bastante sencilla, EF 4.1 Code First esta pensado para trabajar por convenciones en lugar de configuraciones (es por eso que al crear nuestras clases POCO tuvimos en cuenta ciertas consideraciones). El resto es historia conocida: cada clase se corresponderá con una tabla, cada propiedad una columna de la misma y cada instancia de dichas clases representará un registro en la base de datos.

Para ver en funcionamiento nuestro contexto, vamos a trabajar sobre un nuevo controlador llamado AgendaController y en las diferentes acciones armaremos consultas para persistir y recuperar los datos de nuestro modelo:

1: using System.Linq;
2: using System.Web.Mvc;
3: using MvcAndEF.Models;
4:
5: namespace MvcAndEF.Controllers
6: {
7:     public class AgendaController : Controller
8:     {
9:         DatosContext datos = new DatosContext();
10:
11:         public ActionResult Index()
12:         {
13:             var agendas = from a in datos.Agendas
14:                           select a;
15:
16:             return View(agendas.ToList());
17:         }
18:
19:         public ActionResult Create()
20:         {
21:             return View();
22:         }
23:
24:         [HttpPost]
25:         public ActionResult Create(Agenda model)
26:         {
27:             if (ModelState.IsValid)
28:             {
29:                 datos.Agendas.Add(model);
30:                 datos.SaveChanges();
31:
32:                 return RedirectToAction("Index");
33:             }
34:
35:             return View(model);
36:         }
37:
38:         public ActionResult Edit(int id)
39:         {
40:             var agenda = datos.Agendas.Single(a => a.AgendaId == id);
41:             return View(agenda);
42:         }
43:
44:         [HttpPost]
45:         public ActionResult Edit(Agenda model)
46:         {
47:             if(ModelState.IsValid)
48:             {
49:                 var agenda = datos.Agendas.Single
50:                             (a => a.AgendaId == model.AgendaId);
51:                 agenda.Propietario = model.Propietario;
52:                 agenda.FechaCreacion = model.FechaCreacion;
53:
54:                 datos.SaveChanges();
55:
56:                 return RedirectToAction("Index");
57:             }
58:
59:             return View(model);
60:         }
61:     }
62: }

En cada uno de los métodos de acción podemos observar ejemplos de las consultas básicas: selección, inserción y actualización de una entidad. Lo siguiente será crear cada una de las vistas para dichos métodos (lo cual se los dejo de tarea).

Ya tenemos todo listo y aún seguimos sin noticias de la base de datos 🙂 . Pues bien, es hora de que hablemos un poco de ella.

Existen dos estrategias a seguir para definir la DB: la primera es crear el esquema de la base de datos con alguna herramienta, como por ejemplo SQL Management Studio. La segunda permitir que EF 4.1 la genere por nosotros!

Por supuesto que vamos a utilizar la última opción y para eso sera necesario que en el archivo de configuración web.config agreguemos una nueva cadena de conexión para nuestra futura base de datos (esta entrada deberá tener el mismo nombre que la clase DbContext que hemos creado, para nuestro ejemplo DatosContext):

1:  <connectionStrings>
2:  <add name="DatosContext"
3:  connectionString= "Data Source=|DataDirectory|Datos.sdf"
4:  providerName= "System.Data.SqlServerCe.4.0 "/>
5:  </connectionStrings>


Nota: en nuestro caso vamos a usar como proveedor SQL Server Compact Edition 4.0 pero podriamos utilizar SQL Sever o MySql con solo modificar dicho parámetro dentro de la cadena de conexión.

Ahora simplemente ejecutamos y ya podremos crear nuestras primeras entidades:

Nuestra app corriendo

Nuestra app corriendo

Entramos al alta de Agendas:

Formulario de alta

Formulario de alta

Y creamos nuestra primer entidad:

Agregando nuestra primer entidad

Agregando nuestra primer entidad

Como podemos ver, los datos se guardaron sin necesidad de tener que crear manualmente la DB. Validemos esto abriendo el explorador de soluciones:

Base de datos creada

Base de datos creada

EF para generar automaticamente nuestra base de datos buscara dentro del archivo de configuración una cadena de conexión que tenga el mismo nombre que la clase heredada de DbContext y utilizando esta información creará el archivo correspondiente:

Modelo sobre el cual EF se basa para crear la DB

Modelo sobre el cual EF se basa para crear la DB

Podremos inspeccionar la base de datos desde el explorador de servidores (para poder visualizar la DB creada con SQL Server CE 2.0 deberemos instalar previamente el Visual Studio 2010 SP1):

Estructura de la DB creada

Estructura de la DB creada

La tabla EdmMetadata contiene información acerca de la estructura de los objetos del modelo utilizados al momento de crear la base de datos.

Para finalizar, supongamos que tenemos que modificar el modelo, deberiamos redefinir nuestra DB cierto? por defecto EF4.1 al detectar una modificación en el modelo no modifica la estructura de nuestra DB, solamente el contenido de la tabla EdmMetadata.

Para solucionar esto tenemos distintas maneras de sincronizar el modelo con la base de datos: una es hacerlo de forma manual, modificando la estructura de la tabla/s afectadas. Sin embargo existe una manera mucho mas simple para el desarrollador y es por medio del método DropCreateDatabaseIfModelChanges que viene incluida en la libería de EF4.1.

Para esto debemos agregar la siguiente línea en el método Application_Start() del archivo global.asax:

1: Database.SetInitializer<DatosContext>
2:     (new DropCreateDatabaseIfModelChanges<DatosContext>());

Como bien lo dice su nombre, este mecanismo lo que hace es eliminar y volver a crear la base de datos, por lo que todos los registros previamente grabados se perderan. Sin embargo, una forma de solucionar este problema es insertar automáticamente registros cada vez que se genere la base de datos, y la forma de hacerlo es creando una nueva clase “inicializadora” (habré inventado una nueva palabra?) que herede de DropCreateDatabaseIfModelChanges<T> donde T sera DatosContext y en la cual vamos a sobre-escribir el método Seed():

1: public class DatosInitializer : 
2:              DropCreateDatabaseIfModelChanges <DatosContext >
3: {
4:     protected override void Seed(DatosContext context)
5:     {
6:         Agenda agenda = new Agenda ()
7:         {
8:             Propietario = "Sebis" ,
9:             FechaCreacion = DateTime .Now
10:         };
11:
12:         context.Agendas.Add(agenda);
13:     }
14: }


Ahora solo resta modificar la línea que hemos escrito anteriormente dentro de global.asax para que cada vez que se vuelva a generar la base de datos, se inserten dichos registros:

1: Database.SetInitializer(new DatosInitializer ());


Resumiendo, EF 4.1 CF me parece muy recomendable para utilizar en desarrollos de pequeña escala, y ademas facilita  enormemente ciertas tareas al desarrollador, como por ejemplo evitar muchas de las configuraciones que siempre molestan a la hora de ponerse a programar.

En la proxima entrada vamos a ver como podemos integrar los validadores de ASP.NET MVC (Data Anottations) con EF4.1.

Espero que les sea de utilidad!

NHibernate en .NET

NHibernate es un ORM (Object/Relational Mapping) cuyo propósito principal es el mapeo entre entidades de una base de datos y objetos de una aplicación,  permitiéndonos mover información de la base de datos a objetos y viceversa. NHibernate (desde adelante NH) originalmente se desarrollo para Java, y luego surgió una versión que se adapto al framework .NET.

Es importante también destacar que NH es software libre y la URL del proyecto es http://nhforge.org.

En este post vamos a crear una aplicaeción .NET e implementar NH para el acceso a los datos (si trabajáramos con una arquitectura de N-Capas, lo utilizaríamos en la DAO). El primer paso es descargar los binarios desde el sitio del proyecto y descomprimirlos en alguna carpeta de su equipo. Para cuando escribí este post descargue la versión 3.0.0.CR1.

Bien, el siguiente paso será crear una solución en Visual Studio 2010 (o la versión que prefieran) y agregar un proyecto del tipo biblioteca de clases. En el mismo vamos a agregar las siguientes referencias desde la ubicación donde descomprimimos nuestros archivos en el paso uno (más precisamente dentro del directorio Required_Bins):

Referencias a NHibernate

Referencias a NHibernate

Dentro de este proyecto vamos a crear una entidad de negocio que denominaremos Usuario:

public class Usuario
{
    public int Id { get; set; }
    public string Nombre { get; set; }
    public int Edad { get; set; }
    public bool Habilitado { get; set; }
}

Esta clase representa una entidad de nuestra aplicación y dentro del proyecto la crearemos dentro de la carpeta “Entities” para una mejor organización.

Pues bien, por el momento no vimos nada raro. Ahora lo que trataremos de hacer es persistir-recuperar instancias de esta entidad desde una base de datos. Pero antes de continuar vamos a crear en nuestra base de datos la tabla Usuarios con la siguiente estructura:

Tabla Usuarios

Tabla Usuarios

Ahora tenemos que relacionar nuestra entidad Usuario con nuestra tabla Usuarios. Para esto debemos hacer el mapeo correspondiente entre ellas y lo primero que vamos a crear es el archivo XML Usuario.hbm.xml dentro de la carpeta Mappers de nuestro proyecto (a modo informativo: dentro del nombre del archivo XML incluimos “hbm” debido a que por convención NHibernate reconoce a los archivos de mapeo de esa forma).

El archivo XML de mapping es el nucleo de la aplicación, ya que el mismo tiene la correspondencia entre el formato de base de datos y el del objeto.

Antes de comenzar a armar el mapping, vamos a buscar dentro del directorio en el que descargamos las librerías de NH un archivo llamado nhibernate-mapping.xsd el cual vamos a moverlo dentro de una nueva carpeta del proyecto, en nuestro caso la llamaremos ”Recursos”. Este archivo vamos a asociarlo nuestro XML de usuarios recientemente creado: haciendo click derecho sobre el XML, vamos a propiedades y en Esquemas ponemos el path correspondiente al XSD.

Asociando nuestro XML de mapeo al schema de NH.

Asociando nuestro XML de mapeo al schema de NH.

A modo informativo: en Visual Studio, si queremos que un archivo XML se valide contra un schema y además tener disponible la funcionalidad de Intellisense, es necesario asociarlo al XSD correspondiente. Para una correcta definición de schemmas ver el siguiente enlace aquí.

Bien, llego el momento de configurar el mapeo!. Cada archivo de mapping que creemos deberé tener es siguiente nodo padre:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="NHibernateLibrary"
                   namespace="NHibernateLibrary.Entities">

</hibernate-mapping>

En este nodo vamos a setear dos propiedades importantes, el assembly de nuestra aplicación y el namespace donde está nuestra entidad creada. Esto nos evita tener que escribir los namespaces completos de nuestras clases en otras partes del XML.

Bien, llego el momento de comenzar a armar el mapping correspondiente:

<?xml version="1.0" encoding="utf-8" ?>
   <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                      assembly="NHibernateLibrary"
                      namespace="NHibernateLibrary.Entities">

      <class name="Usuario" table="Usuarios">
         <id name="Id"></id>
         <properties name="Nombre"></properties>
         <properties name="Edad"></properties>
         <properties name="Habilitado"></properties>
      </class>

</hibernate-mapping>

Podemos ver que el id lo definimos de una manera diferente al resto de las propiedades, esto nos permite indicarle que dicha propiedad se mapeara con la clave primaria de la tabla. Una de las cosas que debemos tener en cuenta, es que en el caso de que la propiedad se llame igual a la columna de la tabla a la que estamos mapeando, no hace falta indicarlo. En nuestro caso las propiedades se llaman igual, pero no la clase y la tabla, por lo tanto debemos indicar esto asignando el atributo “table”. Lo mismo ocurre con los tipos de datos, por ejemplo veamos la definición de una propiedad que no se corresponde con el nombre de la columna en la tabla:

   <property name="Nombre" column="Name"/>

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 cargarán hasta que sean utilizadas. Este funcionamiento se logra mediante un proxy y NH se encarga de manejarlo internamente.

Bien, tenemos el mapeo armado, ahora configuremos la información de nuestra base de datos. Para esto vamos a crear un nuevo archivo XML llamado hibernate.cfg.xml (el cual contendrá la configuración necesaria para conectarnos a la base de datos). El mismo lo ubicaremos dentro del directorio “Config” y antes de continuar seteamos la propiedad “Copiar en el directorio de resultados” con el valor “Copiar siempre”, porque de no realizar este cambio los archivos de mapeo y configuración no serán incluidos dentro del assembly final. Nota: realizar las misma configuración con nuestro archivo de mapeo.

Propiedades XML de configuración

Propiedades XML de configuración

También le asignaremos el siguiente esquema (para esto buscaremos el archivo nhibernate-configuration.xsd dentro de lo descargado al inicio y lo pondremos de la carpeta “Recursos”):

Asigando el schema a nuestro archivo de configuración.

Asigando el schema a nuestro archivo de configuración.

Bien, llego el momento de realizar la configuración:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-configuration xmlns="urn:nhibernate-configuration-2.2">  
   <session-factory>    
      <property name="connection.provider">NHibernate.Connection.DriverConnectionProvider</property>    
      <property name="dialect">NHibernate.Dialect.MsSql2008Dialect</property>    
      <property name="connection.driver_class">NHibernate.Driver.SqlClientDriver</property>    
      <property name="connection.connection_string">Server=XXXX;database=NHExample;Integrated Security=SSPI;</property>    
      <property name="show_sql">true</property>  
   </session-factory>
</hibernate-configuration>

Lo primero que debemos hacer es configurar el dialecto o idioma de la DB con la que vamos a trabajar. En nuestro caso vamos hacerlo con una base de datos SQL Server 2008, por lo tanto el dialecto será el correspondiente a dicho motor, lo mismo para el driver. Para ver los distintos tipos de base de datos que soporta NHibernate (los cuales son muchísimos!) podemos darle un vistazo al namesapce NHibernate.Dialect:

Algunos de los motores de base de datos soportados.

Algunos de los motores de base de datos soportados.

Bien llegado a este punto tenemos terminada las configuraciones de mapeo y de base de datos. El próximo paso será crear una clase que instanciada nos permita conectarnos mediante NH a la base de datos y exponernos un objeto del tipo ISession para poder realizar las operaciones CRUD (create, read, update and delete) contra la DB. A dicha clase la llamaremos NHibernateManager:

public class NHibernateManager : IDisposable
{
    private static ISessionFactory _sessionFactory;
    public ISession Session;

    public NHibernateManager()
    {
        CreateSession();
        OpenSession();
    }

    private void CreateSession()
    {
        if (_sessionFactory == null)
        {
            var configuration = new Configuration().Configure("Config/hibernate.cfg.xml");
            configuration.AddAssembly("NHibernateLibrary");
            _sessionFactory = configuration.BuildSessionFactory();
        }

        Session = OpenSession();    
   }

   public static ISession OpenSession()
   {
        return _sessionFactory.OpenSession();
   }

   public static void CloseSession()
   {
        _sessionFactory.Dispose();
   }

   #region Miembros de IDisposable
   public void Dispose()
   {
        CloseSession();
   }
   #endregion
}

Ahora vamos a crear nuestras clases encargadas de las operaciones CRUD de nuestras entidades. Para esto vamos a crear una interfaz donde vamos a escribir las firmas para estas operaciones y luego implementarlas. La interfaz vamos a llamarla IUsuarioRepository:

public interface IUsuarioRepository
{
    void Add(Usuario usuario);
    void Update(Usuario usuario);
    void Remove(Usuario usuario);
    Usuario GetById(int id);
    Usuario GetByNombre(string nombre);
}

Y ahora la implementación de la misma en la clase UsuarioRepository (dentro de cada uno de los métodos podemos observar como realizan los distintos tipos de operaciones por medio de NH):

public class UsuarioRepository : IUsuarioRepository
{
   #region Miembros de IUsuarioRepository
   public void Add(Usuario usuario)    
   {
        using (NHibernateManager manager = new NHibernateManager())
        {
            using (ITransaction transaction = manager.Session.BeginTransaction())
            {
                manager.Session.Save(usuario);
                transaction.Commit();
            }
        }
   }
   public void Update(Usuario usuario)
   {
        using (NHibernateManager manager = new NHibernateManager())
        {
            using (ITransaction transaction = manager.Session.BeginTransaction())
            {
                manager.Session.Update(usuario);
                transaction.Commit();
            }
        }
    }
    public void Remove(Usuario usuario)
    {
        using (NHibernateManager manager = new NHibernateManager())
        {
            using (ITransaction transaction = manager.Session.BeginTransaction())
            {
                manager.Session.Delete(usuario);
                transaction.Commit();
            }
        }
    }
    public Usuario GetById(int id)
    {
        using (NHibernateManager manager = new NHibernateManager())
        {
            return manager.Session.Get<Usuario>(id);
        }
    }
    public Usuario GetByNombre(string nombre)
    {
        using (NHibernateManager manager = new NHibernateManager())
        {
            return manager.Session.CreateCriteria(typeof(Usuario)).Add(Restrictions.Eq("Nombre", nombre)).UniqueResult<Usuario>();
        }
    }
    #endregion
}

Bueno, para validar que todo lo realizado sea correcto vamos a crear los test correspondientes para cada tipo de operación CRUD, en este caso vamos a realizar los test con NUnit:

[TestFixture]
public class NHibernateUsuarioTest
{
    private UsuarioRepository repositorio = null;

    [SetUp]
    public void Setup()
    {
        repositorio = new UsuarioRepository();
    }

    [Test]
    public void DeberíaObtenerUsuarioPorElId()
    {
        int id = 1;
        Assert.AreEqual(id, repositorio.GetById(id).Id);
    }

    [Test]
    public void DeberíaObtenerUsuarioPorElNombre()
    {
        string nombre = "Sebis";
        Assert.AreEqual(nombre, repositorio.GetByNombre(nombre).Nombre);
    }

    [Test]
    public void DeberíaCrearUsuario()
    {
        var nuevoUsuario= new Usuario { Nombre = "Juan", Edad = 28, Habilitado = true };
        repositorio.Add(nuevoUsuario);

        var usuario = repositorio.GetById(nuevoUsuario.Id);

        Assert.IsNotNull(usuario);
        Assert.AreNotSame(nuevoUsuario, usuario);
        Assert.AreEqual(nuevoUsuario.Nombre, usuario.Nombre);
        Assert.AreEqual(nuevoUsuario.Edad, usuario.Edad);
        Assert.AreEqual(nuevoUsuario.Habilitado, usuario.Habilitado);
    }

    [Test]
    public void DeberíaActualizarUsuario()
    {
        var editUsuario = repositorio.GetById(1);
        editUsuario.Nombre = "Sebis";
        editUsuario.Edad = editUsuario.Edad + 1;
        editUsuario.Habilitado = false;

        repositorio.Update(editUsuario);

        var usuario = repositorio.GetById(editUsuario.Id);

        Assert.IsNotNull(usuario);
        Assert.AreNotSame(editUsuario, usuario);
        Assert.AreEqual(editUsuario.Nombre, usuario.Nombre);
        Assert.AreEqual(editUsuario.Edad, usuario.Edad);
        Assert.AreEqual(editUsuario.Habilitado, usuario.Habilitado);
    }

    [Test]
    public void DeberíaEliminarUsuario()
    {
        var nuevoUsuario = new Usuario { Nombre = "Tito", Edad = 30, Habilitado = true };
        repositorio.Add(nuevoUsuario);

        var id = nuevoUsuario.Id;
        repositorio.Remove(nuevoUsuario);
        Usuario usuario = repositorio.GetById(id);

        Assert.IsNull(usuario);
        }

    [TearDown]
    public void TearDown()
    {
        repositorio = null;
    }
}

Corremos los test y validamos que los mismos sean correctos:

Resultados de los test

Resultados de los test

Finalmente realizaremos un ejemplo bien simple sobre una aplicación de consola:

class Program
{
    static void Main(string[] args)
    {
        UsuarioRepository repositorio = new UsuarioRepository();
        var u = repositorio.GetById(1);

        Console.Write(string.Format("Nombre: {0}, Edad: {1}, Habilitado: {2}", u.Nombre, u.Edad, u.Habilitado));
        Console.ReadLine();
    }
}

Cuando ejecutemos veremos en la consola que antes de imprimir el resultado, se muestra la consulta SQL que hace NH para recuperar los datos, esto es debido a que en la propiedad show_sql que seteamos en el XML de configuración la seteamos en true.

Resultado en consola

Resultado en consola

Eso es todo gente, existe muchísima información y cuestiones sobre este tema (por ejemplo cuando nuestras clases tienen otras clases como propiedades, la forma de manejar las sesiones, la forma de armar los test unitarios, etc), la idea fue darles una introducción básica al tema para que desde aquí puedan arrancar.

Espero que le sea de utilidad!