刷新NHibernate同时仍然允许事务回滚

时间:2009-11-19 05:13:45

标签: nhibernate transactions flush

我正在尝试将NHibernate与未与NHibernate映射的遗留实体一起使用。有时这意味着我需要手动将NHibernate数据刷新到数据库,这样当我尝试将遗留实体与NHibernate映射实体连接时,我就不会收到外键异常。

当在需要回滚的事务中发生此问题时会发生问题。从NHibernate刷新的数据不会回滚。

我能做些什么吗?

更新

仍然很好奇如何做到这一点 - 我不相信给出的任何答案都能解决这个问题。我需要调用Flush()。问题是,如何回滚已刷新的数据?

3 个答案:

答案 0 :(得分:4)

检查一下:Force query execution without flush/commit

我似乎有同样的问题,我会刷新然后我会回滚,但一些数据将保持在数据库中。但是,我的代码中有一些部分会调用一个无法回滚的提交。将接受的答案的代码片段视为事务,刷新,回滚和提交的正确用法,并考虑到可以扩展此模式......

在单个工作单元中(即我们将Web应用程序中的请求视为单个工作单元,并且该请求中发生的所有事情都存在于提交onEndRequest的单个事务中):

  1. 您只需拨打一次_sessionFactory.OpenSession()_session.BeginTransaction()_session.CommitTransaction()_session.CloseSession()

  2. 您可以根据需要多次调用_session.Flush()_session.RollBackTransaction(),但会自动在提交时自动调用Flush()。当您需要进行查询并确保所提取的数据不会过时时,您可能需要调用Flush。

  3. 请注意,提交事务一旦提交,之后的所有操作都不会发生在该事务上。相反,NHibernate将在幕后创建必要的事务(http://www.nhprof.com/Learn/Alerts/DoNotUseImplicitTransactions) 您已经在跟踪一致性和可能的​​逻辑完整性方面遇到了问题

  4. 如果你真的必须在工作单元中间调用commit,强烈建议在那时创建一个新的事务,以便你可以明确地管理它

  5. 更好的是尝试嵌套交易,据称允许部分提交;您可以回滚“root”事务,所有更改都将被还原。我还没有真正测试过.NET和SQL Server的这个功能,虽然数据库中的嵌套事务本身还有很多不足之处,我不知道ADO.NET究竟如何支持这个功能。

  6. 从1。1开始,所有版本的NHibernate都测试了1到4点。

答案 1 :(得分:3)

为了格式化,我允许自己在这里更新tolism7的答案。

  1. 使用using并忘记transaction.Dispose() - transaction将在使用块的末尾自动为Dispose d。
  2. throw - 不要抛出ex,因为这意味着丢弃你的堆栈跟踪(请参阅this post其中所说的“当.NET Framework执行此语句时:throw ex;它会抛弃所有当前函数上方的堆栈信息。“)
  3. public void CommitChanges()
    {
        using (var transaction = Session.BeginTransaction())  // <-- open scope
            try
            {
                // do something
                transaction.Commit();
            }
            catch (HibernateException)
            {
                transaction.Rollback();
                _session.Close();
                _session.Dispose();
    
                throw;  // <-- this way the stacktrace stays intact!
            }
    }
    

    可以找到VB.NET version这段代码的here

答案 2 :(得分:2)

当与NHibernate一起使用事务时,尽量避免使用Session.Flush(),而是使用在内部调用session.flush()的transaction.Commit()。

如果在Commit()期间发生错误并且需要回滚事务,则可以像这样解决。

public static void CommitChanges()
{
    ITransaction transaction = Session.BeginTransaction();

    try
    {
        transaction.Commit();
    }
    catch (HibernateException ex)
    {
        transaction.Rollback();
        //close and dispose session here
        throw ex;
    }
    finally
    {
        transaction.Dispose();
    }
}

现在,如果手动调用flush()或调用commit()成功完成,则无法使用NHibernate机制回滚事务。 特别是在调用transaction.Commit()命令时,NHibernate创建的AdoTransaction会在Commit()完成后立即处理,因此您无法访问它以便回滚。

上面的代码示例允许您捕获在提交期间发生的错误,然后回滚已经启动的事务。

现在,不再调用上面示例中的transaction.Commit(),而是在我的测试中调用session.Flush(),因为事务永远不会被提交,所以数据不会保存在数据库中。

我不知道你的代码是怎么样的,但是如果你正在调用一个模式,如上面的代码示例所示,transaction.commit()而不是Session.Flush()它应该给你一个方法实现你想要的。