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!