Estoy tratando de encontrar la mejor solución para manejar transacciones en una aplicación web que utiliza NHibernate.NHibernate, transacciones y TransactionScope
Usamos un IHttpModule y en HttpApplication.BeginRequest abrimos una nueva sesión y la vinculamos a HttpContext con ManagedWebSessionContext.Bind (context, session); Cerramos y desenlazamos la sesión en HttpApplication.EndRequest.
En nuestra clase base del repositorio, siempre envuelto en una transacción nuestra saveOrUpdate, Borrar, Get métodos como, según best practice:
public virtual void Save(T entity)
{
var session = DependencyManager.Resolve<ISession>();
using (var transaction = session.BeginTransaction())
{
session.SaveOrUpdate(entity);
transaction.Commit();
}
}
Pero entonces esto no funciona, si es necesario poner un transacción en algún lugar de, por ejemplo un servicio de aplicación para incluir varias llamadas al repositorio para guardar, eliminar, etc.
Entonces, lo que probamos es usar TransactionScope (no quería escribir mi propio gestor de transacciones). Para probar que esto funcionó, utilizo una TransactionScope exterior que no llama integro() para forzar una inversión:
Repositorio Save():
public virtual void Save(T entity)
{
using (TransactionScope scope = new TransactionScope())
{
var session = DependencyManager.Resolve<ISession>();
session.SaveOrUpdate(entity);
scope.Complete();
}
}
El bloque que utiliza el repositorio :
TestEntity testEntity = new TestEntity { Text = "Test1" };
ITestRepository testRepository = DependencyManager.Resolve<ITestRepository>();
testRepository.Save(testEntity);
using (var scope = new TransactionScope())
{
TestEntity entityToChange = testRepository.GetById(testEntity.Id);
entityToChange.Text = "TestChanged";
testRepository.Save(entityToChange);
}
TestEntity entityChanged = testRepository.GetById(testEntity.Id);
Assert.That(entityChanged.Text, Is.EqualTo("Test1"));
Esto no funciona. Pero para mí, si NHibernate es compatible con TransactionScope, ¡lo haría! Lo que ocurre es que no hay ningún ROLLBACK en absoluto en la base de datos, sino cuando testRepository.GetById (testEntity.Id); la instrucción se ejecuta una ACTUALIZACIÓN con SET Text = "TestCahgned" se dispara en su lugar (debería haberse disparado entre BEGIN TRAN y ROLLBACK TRAN). NHibernate lee el valor de la memoria caché de nivel 1 y activa una ACTUALIZACIÓN en la base de datos. No se espera un comportamiento? Por lo que entiendo cada vez que se realiza una reversión en el ámbito de NHibernate, también debe cerrar y desvincular la sesión actual.
Mi pregunta es: ¿Alguien sabe de una buena manera de hacer esto usando TransactionScope y ManagedWebSessionContext?
Si está utilizando TransactionScope, es necesario utilizar NHibernate 2.1. Es solo con 2.1 que NH realmente obtuvo una buena integración con TransactionScope. –