我正在尝试找到在使用NHibernate的Web应用程序中处理事务的最佳解决方案。
我们使用IHttpModule,在HttpApplication.BeginRequest时打开一个新会话,并使用ManagedWebSessionContext.Bind(context,session)将其绑定到HttpContext。我们在HttpApplication.EndRequest上关闭和取消绑定会话。
在我们的存储库基类中,我们始终像最佳实践中所述一样,在我们的SaveOrUpdate、Delete、Get方法周围包装了一个事务:
public virtual void Save(T entity)
{
var session = DependencyManager.Resolve<ISession>();
using (var transaction = session.BeginTransaction())
{
session.SaveOrUpdate(entity);
transaction.Commit();
}
}
但是,如果您需要在应用程序服务中放置事务以包括多个存储库调用(保存、删除等),则这种方法将不起作用。
因此,我们尝试使用TransactionScope(我不想编写自己的transactionmanager)。为了测试它是否有效,我使用一个外部TransactionScope,它不调用.Complete()来强制回滚:
存储库Save():
public virtual void Save(T entity)
{
using (TransactionScope scope = new TransactionScope())
{
var session = DependencyManager.Resolve<ISession>();
session.SaveOrUpdate(entity);
scope.Complete();
}
}
使用存储库的代码块:
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"));
这不起作用。但对我来说,如果NHibernate支持TransactionScope,它就会起作用!发生的情况是数据库中根本没有回滚,但是当执行testRepository.GetById(testEntity.Id); 语句时,会触发一个带SET Text =“TestCahgned”的UPDATE(它应该在BEGIN TRAN和ROLLBACK TRAN之间触发)。 NHibernate从级别1缓存中读取值,并向数据库发送UPDATE。这不是预期的行为吗?从我所了解的每当在NHibernate范围内执行回滚时,您还需要关闭和解绑定当前会话。
我的问题是:是否有人知道使用TransactionScope和ManagedWebSessionContext完成此操作的好方法?