我正在尝试将 NHibernate 与未使用 NHibernate 映射的遗留实体一起使用。有时这意味着我需要手动将 NHibernate 数据刷新到数据库,这样当我尝试将遗留实体与 NHibernate 映射的实体连接时,我不会收到外键异常。
当这发生在需要回滚的事务中时,就会出现问题。从 NHibernate 刷新的数据不会回滚。
对此我能做些什么吗?
更新
仍然很好奇如何做到这一点 - 我不相信给出的任何一个答案都解决了这个问题。我需要调用 Flush()。问题是,如何回滚已刷新的数据?
我正在尝试将 NHibernate 与未使用 NHibernate 映射的遗留实体一起使用。有时这意味着我需要手动将 NHibernate 数据刷新到数据库,这样当我尝试将遗留实体与 NHibernate 映射的实体连接时,我不会收到外键异常。
当这发生在需要回滚的事务中时,就会出现问题。从 NHibernate 刷新的数据不会回滚。
对此我能做些什么吗?
更新
仍然很好奇如何做到这一点 - 我不相信给出的任何一个答案都解决了这个问题。我需要调用 Flush()。问题是,如何回滚已刷新的数据?
检查这个:强制执行查询而不刷新/提交
我似乎有同样的问题,我会刷新然后我会回滚,但一些数据会保留在数据库中。但是,我的代码中有一些部分会调用提交,并且无法回滚。将接受的答案的代码片段视为事务、刷新、回滚和提交的正确用法,并考虑到这种模式可以扩展......
在单个工作单元中(即,我们将 Web 应用程序中的请求视为单个工作单元,并且该请求中发生的所有事情都存在于提交 onEndRequest 的单个事务中):
您调用_sessionFactory.OpenSession(), _session.BeginTransaction(),_session.CommitTransaction()并且_session.CloseSession()只有一次。
您可以根据需要调用多次_session.Flush(),_session.RollBackTransaction()但 Flush() 会在提交时自动调用。当您需要进行查询并确保获取的数据不会过时时,您可能需要调用 Flush。
请注意,一旦提交事务被提交,之后的所有操作都不会发生在该事务上。相反,NHibernate 将在后台创建必要的事务(http://www.nhprof.com/Learn/Alerts/DoNotUseImplicitTransactions),此时您已经在跟踪一致性和可能的逻辑完整性时遇到了问题
如果您确实必须在工作单元中间调用 commit,强烈建议您在此时创建一个新事务,以便您可以显式管理它
更好的是尝试嵌套事务据称会允许部分提交;您可以回滚“根”事务,所有更改都将被还原。我还没有真正测试过 .NET 和 SQL Server 的这个特性,尽管数据库中的嵌套事务本身还有很多不足之处,而且我不知道 ADO.NET 如何准确地检测这个特性。
从 1.2 开始,所有版本的 NHibernate 都对第 1 点到第 4 点进行了测试。
为了格式化,我允许自己在这里更新 tolism7 的答案。
using并忘记 transaction.Dispose() -在 using 块的末尾transaction将自动被'd'。Disposethrow- 不要抛出 ex,因为这意味着丢弃你的堆栈跟踪(请参阅这篇文章,其中指出“当 .NET 框架执行此语句时:throw ex;它会丢弃当前函数上方的所有堆栈信息。”).
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!
}
}
当使用 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() 它应该为您提供一种实现您所想的方法想。