我正在尝试找到在使用 NHibernate 的 Web 应用程序中处理事务的最佳解决方案。
我们使用 IHttpModule 并在 HttpApplication.BeginRequest 我们打开一个新会话并使用 ManagedWebSessionContext.Bind(context, session); 将其绑定到 HttpContext;我们关闭并取消绑定 HttpApplication.EndRequest 上的会话。
根据最佳实践,在我们的 Repository 基类中,我们总是围绕 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(我不想编写自己的事务管理器)。为了测试这是否有效,我使用了一个不调用 .Complete() 的外部 TransactionScope 来强制回滚:
存储库保存():
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 它会!发生的情况是数据库中根本没有 ROLLBACK 但是当 testRepository.GetById(testEntity.Id); 语句执行了一个带有 SET Text = "TestCahgned" 的 UPDATE 代替触发(它应该在 BEGIN TRAN 和 ROLLBACK TRAN 之间触发)。NHibernate 从 level1 缓存中读取值并触发 UPDATE 到数据库。不是预期的行为!?据我了解,每当在 NHibernate 范围内完成回滚时,您还需要关闭并取消绑定当前会话。
我的问题是:有谁知道使用 TransactionScope 和 ManagedWebSessionContext 的好方法?