NHibernate 3.0:TransactionScope和自动刷新

7
在NHibernate 3.0中,当仅在环境事务下运行(即未启动NHibernate事务)时,FlushMode.Auto无法工作。是否应该这样?
using (TransactionScope scope = new TransactionScope()) 
{
    ISession session = sessionFactory.OpenSession();
    MappedEntity entity = new MappedEntity() { Name = "Entity", Value = 20 };
    session.Save(entity);

    entity.Value = 30;
    session.SaveOrUpdate(entity);

    // This returns one entity, when it should return none
    var list = session.
               CreateQuery("from MappedEntity where Value = 20").
               List<MappedEntity>();
}

(例子无耻地从this related question中窃取)

在NHibernate源代码中,我可以看到它正在检查是否存在正在进行的事务(在SessionImpl.AutoFlushIfRequired中),但相关方法(SessionImpl.TransactionInProgress)不考虑环境事务 - 不像它的表亲ConnectionManager.IsInActiveTransaction,它考虑环境事务。


感谢您上面的详细分析,我已将其添加到工单中,修复应该在NH 4.1.x.x版本中完成。 - baHI
无论如何,针对上述代码:有时候你无法避免在同一事务中保存和读取。但是在你的情况下(大多数情况下),没有必要在该事务内进行读取。另一种可能性是在读取之前执行session.Flush()。我知道这应该是NHibernate应该做的事情,但是... - baHI
4个回答

6

好消息。 感谢Jeff Sternal(他很好地识别了问题),我更新了https://nhibernate.jira.com/browse/NH-3583,并且由于NH工作人员的努力,已经有了修复和拉取请求,因此在即将发布的4.1.x.x版本中,这个问题将被修复。


NH的最新版本已经发布在NuGet上,因此这个问题现在已经得到解决。 - baHI

3

您应该始终使用明确的NHibernate事务。

using (TransactionScope scope = new TransactionScope()) 
using (ISession session = sessionFactory.OpenSession())
using (ITransaction transaction = session.BeginTransaction())
{
    //Do work here
    transaction.Commit();
    scope.Complete();
}

我看到你也在NH开发者列表中写了一些东西 - 虽然这可能会在将来发生变化,但现在就是这样运作的。


1
不争论该指导方针的优点(Ayende在多个场合都有质疑),它并没有回答我的问题,我的问题并不是关于代码当前如何运行。实际上,我的问题是关于理想行为的:在环境事务下自动刷新是否仅仅是可取的?反之,是否有任何理由NHibernate(或者其他任何ORM)不应该在环境事务下自动刷新? - Jeff Sternal
我认为在他的一些帖子中,Ayende也提到了环境事务的工作原理。因此,如果您使用环境事务并嵌套它们,则上述代码将导致错误,就像@brad在Oracle中描述的那样。不管怎样,开发人员已经修复了该错误,当NH 4.1.x.x推出时,一切都会正常运行... - baHI

2
Diego提供的答案不适用于使用Oracle数据库的情况。(相关问题请参见这里)。由于连接已经成为事务的一部分,会话(session).BeginTransaction将失败。
看起来我们必须在我们的应用程序(WCF、NHibernate、Oracle)中编写一些代码来解决这个问题,但这似乎是NHibernate应该开箱即用提供的功能。如果有人有好的答案,那将非常感激。

0
对我而言,我不知道背后的原因,但在会话结束之前强制刷新会话似乎对我有用。例如: 使用(会话) { //做你的工作

session.Flush(); }

我验证了这个方法可以在我的分布式事务中使用,如果不这样做,当TransactionScope被处理时,我总是会得到“事务已中止”的错误信息。

即使将session.FlushMode设置为Commit对我也没有用。


是的,即使在提交时自动冲洗,使用分布式事务也会失败。我认为线程也存在一些问题。在 NServicebus 中使用了代码:Thread.Sleep(10) :D还有…… - baHI

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接