【问题标题】:NHibernate ExecuteUpdate does not participate in current transaction?NHibernate ExecuteUpdate 不参与当前事务?
【发布时间】:2014-12-13 05:47:38
【问题描述】:
我的代码如下所示:
using (var session = this.sessionCreator.OpenSession())
using (var transaction = session.BeginTransaction())
{
session.SaveOrUpdate(anObject);
session.CreateSQLQuery(sql)
.ExecuteUpdate();
transaction.Commit();
}
令人惊讶的是,SQL 查询在anObject 被保存之前执行。显然,ExecuteUpdate 命令不参与当前事务。有没有办法让更新加入交易?
【问题讨论】:
标签:
nhibernate
transactions
【解决方案1】:
NHibernate 事务与 DB 事务不同;框架无法知道您的ExecuteUpdate 正在影响哪些实体或哪些数据,因此不会自动刷新SaveOrUpdate(可能会根据会话的FlushMode)和CreateSQLQuery 之间的会话(如果你使用ExecuteUpdate,它总是立即生效)。
一般来说,如果您将 NHibernate 逻辑与较低级别的 SQL 逻辑(存储过程等)相结合,那么您将需要使用 TransactionScope 以保证原子性:
using (var tsc = new TransactionScope())
using (var session = sessionFactory.OpenStatelessSession())
using (var transaction = session.BeginTransaction())
{
session.SaveOrUpdate(entity);
session.Flush();
session.CreateSQLQuery("EXEC foo").ExecuteUpdate();
transaction.Commit();
tsc.Complete();
}
(FWIW - 严格来说,NHibernate 事务在这里应该是不必要的,因为在 Flush 之后您实际上并没有对会话做任何事情 - 但无论如何最好使用显式 NH 事务以防逻辑发生变化未来。)
请注意,我更喜欢将IStatelessSession 实例用于任何批量插入/更新/等。 - 如果您使用常规的ISession 实例并且需要实际检索ExecuteUpdate 所做的更新,那么您可能需要使用会话的Evict 或Clear 方法来保证获得更新。
【解决方案2】:
我不确定您使用的是哪个版本的 NHibernate,但鉴于现在是 2 年后很可能您的答案适用于早期版本。我正在使用 3.3.3.GA 并且 NHibernate 事务能够毫无问题地管理 SQL Query ExecuteUpdate。我检查了在运行 transaction.Commit() 之前我无法看到提交的数据。
using (var session = sessionFactory.OpenStatelessSession())
using (var transaction = session.BeginTransaction())
{
session.SaveOrUpdate(entity);
session.Flush();
session.CreateSQLQuery("EXEC foo").ExecuteUpdate();
transaction.Commit();
}