Tag Archive for nhibernate

FluentNhibernate y Sql-query

Hoy en la oficina uno de mis compañeros de trabajo me presenta un simple problema muy particular

Necesito llamar a un procedimiento almacenado desde NHibernate, pero estoy usando FluentNhibernate para el mapeo de entidades, ¿hay algo que puedo hacer?

No es algo así como un problema “clásico” el tener que llamar procedimientos almacenados en Nhibernate, pero creo que vale la pena explicarlo.

Digamos que el procedimiento almacenado sea algo como esto

CREATE PROCEDURE [dbo].[usp_GetItemCount](@parentId INT) AS
BEGIN
    SELECT COUNT(*) AS [Total]
    FROM [items]
    WHERE [parent_id] = @parentId
END

Bueno, nada complicado, pero digamos que necesitamos llamarlo desde algún lugar de nuestra aplicación. Digamos que debido a que es algo fuera de la entidad de negocio necesitamos hacerlo usando un servicio. Bueno, escribamos el servicio

public interface ICountService {
    int GetTotal(int parentId);
}

Como recordaran, en NHibernate existe algo llamado named queries utilizadas para ejecutar consultas de SQL arbitrarias en el motor de base de datos, es una herramienta sumamente poderosa, les recomiendo dar una vuelta por la documentación. Una named query se define en un archivo de mapeo HBM al igual que los archivos de mapeo de NHibernate, por lo tanto podemos definir esta named query en el archivo Queries.hbm.xml

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <sql-query name="SampleQuery" cacheable="true"
             read-only="true" callable="true">
    <query-param name="parentId" type="Int32"/>
    <return-scalar type="Int32" column="Total"/>
    exec usp_GetItemCount @parentId = :parentId
  </sql-query>
</hibernate-mapping>

Ok señores, pero digamos que estamos usando Fluent NHibernate para el mapeo de nuestras entidades… Rayos… Bueno, no tanto, en realidad es bastante sencillo, en Fluent Nhibernate tenemos la opción de agregar mapeos de XML al mapeo "fluent"

SessionFactory =
 Fluently.Configure().Database(MsSqlConfiguration.MsSql2008
     .ConnectionString(
         c => c.Server("(local)").Database("Test")
             .TrustedConnection())
         .ShowSql().CurrentSessionContext("web")
         .ProxyFactoryFactory<ProxyFactoryFactory>())
     .Mappings(m => m.FluentMappings.AddFromAssemblyOf<ItemClassMap>())
     .Mappings(m => m.HbmMappings.AddFromAssemblyOf<ItemClassMap>())
     .BuildSessionFactory();

Digamos que el archivo de mapeo de la query se encuentra en el mismo lugar que el de las classmaps de fluent nhibernate. Ahora es sencillo definir el servicio que ejecuta el procedimiento almacenado.

public class CountServiceImpl : ICountService {
    readonly ISessionFactory _factory;
    protected ISession Session {
        get { return _factory.GetCurrentSession(); }
    }

    public CountServiceImpl(ISessionFactory factory) {
        _factory = factory;
    }

    public int GetTotal(int parentId) {
        var total = Session.GetNamedQuery("SampleQuery")
            .SetInt32("parentId", parentId)
            .UniqueResult<int>();
        return total;
    }
}

Simple, sencillo, llano, conciso…

Como siempre para comentarios o lo que quieran decir/compartir/discutir se encuentra la cajita de comentarios en este post… Hasta la próxima!

Mapeando subclases en varios archivos de NHibernate

Creando el mapping de una legacy DB en la oficina, me topé con el mapping de herencia de NHibernate (muy efectivo por cierto). Aunque ya he mapeado herencia anteriormente en NHibernate, algo que irrita de sobremanera es el archivo gigante que se crea ante la clase base. Revisando la documentación de NHibernate me topo con el concepto de mapas modulares para clases de herencia, algo que nos resuelve los dolores de cabeza con mapeos de herencia muy grandes :D

Tomemos por ejemplo este mapping:

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="Sample"
                   namespace="Sample">
  <class name="Member" table="members">
    <id name="Username" column="username">
      <generator class="assigned" />
    </id>
    <discriminator column="type" type="Int32" />
    <property name="FirstName" column="first_name" not-null="true" />
    <property name="LastName" column="last_name" not-null="true" />
    <property name="Email" column="email" not-null="true" />
    <property name="BirthDate" column="birthdate" not-null="true" />
    <joined-subclass table="students" name="Student">
      <key column="student_id" />
            <property name="Added" />
    </joined-subclass>
  </class>
</hibernate-mapping>

(Para comprender un poco más de herencia en nhibernate usando joined-subclass recomiendohttp://www.hibernate.org/hib_docs/nhibernate/1.2/reference/en/html/inheritance.html en la documentación de NHibernate).

Bien, lo feo es que si he de mapear 5 clases heredadas debo agregar cada joined-subclass en el mismo archivo y eso me crearía archivos de mapeo poco portables y de díficil mantenimiento. Es cuando llega a salvar los archivos de mapeo modular.

En el caso anterior movemos la declaración de joined-subclass de Student a su propio archivo hbm y solo variamos agregandole el atributo “extends” indicando que clase (definida en su propio hbm) extendemos.

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
                   assembly="Sample"
                   namespace="Sample">
  <joined-subclass table="students" name="Student"
                   extends="Member">
    <key column="student_id" />
    <property name="Added" />
  </joined-subclass>
</hibernate-mapping>

Sencillo no?

Otro día hablaremos un poco más de nuestro siempre versátil NHibernate ;)