C# NHibernate:在提交事务之前调用Session.Flush()是否有效?

C# NHibernate:在提交事务之前调用Session.Flush()是否有效?,c#,.net,nhibernate,transactions,flush,C#,.net,Nhibernate,Transactions,Flush,我需要在NHibernate的工作单元内执行两个操作:事务性操作(实体保存)和非事务性操作 由于无法回滚非事务性操作,如果在执行非事务性操作(并最终提交事务)之前保存实体,我仍然会得到事务性行为: 仅当两个子操作成功执行时,才会提交操作 如果实体保存失败,则不执行非事务性操作 如果非事务性存储失败,将回滚实体存储 问题是:对于下面这样的代码,NHibernate在调用transaction.Commit()之前(在内部调用session.Flush())不会执行实际的sql插入: 对于这样的

我需要在NHibernate的工作单元内执行两个操作:事务性操作(实体保存)和非事务性操作

由于无法回滚非事务性操作,如果在执行非事务性操作(并最终提交事务)之前保存实体,我仍然会得到事务性行为:

  • 仅当两个子操作成功执行时,才会提交操作
  • 如果实体保存失败,则不执行非事务性操作
  • 如果非事务性存储失败,将回滚实体存储
问题是:对于下面这样的代码,NHibernate在调用transaction.Commit()之前(在内部调用session.Flush())不会执行实际的sql插入:

对于这样的代码,如果Sql插入失败就太晚了:NotTransactionalOperation已经执行。要在执行NotTransactionalOperation之前执行实际的SQL插入,我必须在session.Save()之前显式调用session.Flush():


代码是有效的,但是。。。是否认为在提交事务之前调用session.Flush()是最佳做法?如果没有,有没有更好的方法来达到同样的结果?

这是不寻常的,但是如果你想做一些工作单元之外的事情,而这些事情依赖于内部完成,这是完全有效的。然而,问题就变成了,如果操作依赖于内部的东西,为什么要在工作单元之外执行?如果它是完全依赖于顺序的,那么在执行非事务性操作之前,应该考虑刷新和提交。如果非trans操作确定整个内容是否会提交(例如,可能会抛出异常),那么它应该是工作单元的一部分


此外,non-trans选项可能不必依赖于数据库中的数据,除非它依赖于类似于触发器的数据层代码(尽管我喜欢触发器,但通常应避免使用它们,原因有几个,其中最重要的一个原因是有像这样复杂的保存操作的倾向)。通常,您应该将业务逻辑保留在应用程序层中,但作为最终选项除外。如果对象已经保存到会话中,那么无论该会话是在哪里,数据都是可用的,并且该会话应该在必要时具有广泛的范围(或者,考虑与随时访问父体的儿童共享的“父”会话)。

< P> Flushing意味着NHiBiNATE将确保所有更改都被持久化到DB。也就是说,它将确保执行所有必要的SQL语句。 当事务失败并因此回滚时,所有这些更改都将恢复。因此,我认为这样做没有问题(但是您必须记住,您的实体可能没有处于有效状态,因为事务已经失败)

但是。。。实际上,我看不出有什么问题: 当非事务过程失败时,会出现什么问题?由于该过程是非事务性的,我想它对数据库所保存的信息没有影响?或者,这个代码做什么

如果是非事务性的,为什么不能在工作单位之外进行

当保存失败时,我想您将确保不仅回滚事务,而且还会在堆栈上抛出异常,直到它遇到错误处理程序,这可能意味着您的非事务性代码也不会执行:

using( var transaction = session.BeginTransaction() ) 
{
      repository.Save (entity); 

      transaction.Commit();   // error, exception is thrown.
}

NonTransactionalCode (entity); // this line will not be executed, since the exception will be thrown up the stack until a suitable catch block is encountered.

我知道这有点不寻常,但非事务代码(entity)表示保存到远程硬件设备的实体,db条目表示成功写入该硬件;因此,我不能拥有远程保存未成功的db条目,反之亦然。:)(错误仍然由异常日志机制处理)我的疑问来自于这样一个事实:transaction.Commit在内部调用Flush(),而我最后两次调用Flush()。@notriousxl:别担心,第二次Flush是一个(几乎)noop。如果提交失败,你会怎么做,即使刷新成功?在伪事务上下文中执行这两个操作也是应用程序的先决条件,请参阅我对Frederik的响应。。。db条目类似于成功的NotTransactionalOperation的元表示…:)
        using (var transaction = session.BeginTransaction())
        {
            session.Save(entity);
            session.Flush(); // the actual sql insert will be executed here

            NotTransactionalOperationBasedOn(entity);

            transaction.Commit(); 
        }
using( var transaction = session.BeginTransaction() ) 
{
      repository.Save (entity); 

      transaction.Commit();   // error, exception is thrown.
}

NonTransactionalCode (entity); // this line will not be executed, since the exception will be thrown up the stack until a suitable catch block is encountered.