我正在考虑为NHibernate持久层创建自己的IUnitOfWork
实现。
执行此操作的正确方法似乎是在构造函数中实例化ISession
和ITransaction
,然后将其置于析构函数或Dispose()
方法中。 / p>
当然,如果有人调用Save()
方法,那么ISession
会被刷新,而ITransaction
会完整,所以在调用Save()
后,就不会再次成为Save()
的有效开放交易......除非我提交了第一笔交易并立即开立了另一笔新交易。但这是个好主意吗?
从设计角度来说,进行一次提交操作是有意义的,但我不一定能控制代码,而其他开发人员可能不会遵守UnitOfWork模式。
通过尝试使UnitOfWork容忍每个会话的多个事务,我是否会失去/获得任何东西?我应该检查一个打开的事务,如果它已经被提交则抛出异常,而不是进行新的事务吗?
答案 0 :(得分:11)
回答第一个问题:是的,可以在一个会话中拥有多个交易。
是个好主意吗?这取决于。
问题是第一个事务中的数据更改将被提交,而不确定整个工作单元(会话)是否在最后提交。当你得到一个稍后的事务中的StaleObjectException时,你已经提交了一些数据。请注意,这种异常使您的会话无法使用,无论如何您必须销毁它。然后很难重新开始并再试一次。
我想说,在这种情况下它运作良好:
UI应用
错误由用户以交互方式处理。这意味着用户可以看到错误情况下实际存储的内容,并重复他所做的更改。
更改仅在上次交易中刷新
由NH实施的会话仅在最后或“必要时”刷新更改。因此,在会话提交之前,可以保留内存中的更改。问题是NH需要在每次查询之前刷新会话,这很难控制。它可以关闭,这会导致副作用。在编写简单的事务时,您可以控制它。在一个复杂的系统中,几乎不可能确保没有任何问题。
简单方法(tm)
我编写了一个非常大的客户端 - 服务器系统的持久层。在这样的系统中,您没有用户直接处理错误。您需要处理系统中的错误并以一致的状态将控制权返回给客户端。
我将整个事务处理简化为绝对最小化,以使其稳定并且“白痴证明”。我总是创建一个会话和一个事务,它会被提交或不提交。
答案 1 :(得分:2)
有多个选项可用于实现具有工作单元的nhibernate嵌套事务。
这里我使用Command模式作为工作单元。
public interface IAction
{
void Execute();
}
public abstract class Action<T> : IAction, IDisposable where T : Action<T>
{
public void Execute()
{
try
{
//Start unit of work by your unit of work pattern or
transaction.Begin();
OnExecute();
//End Unit of work
transaction.Commit();
}
catch (Exception e)
{
transaction.Rollback();
throw e;
}
}
protected abstract void OnExecute();
public void Dispose()
{
}
}
public class MyBusinessLogic : Action<MyBusinessLogic>
{
protected override void OnExecute()
{
//Implementation
}
}
public class MyAnotherBusinessLogic : Action<MyAnotherBusinessLogic>
{
protected override void OnExecute()
{
//Nested transaction
MyBusinessLogic logic = new MyBusinessLogic();
logic.Execute();
}
}
答案 2 :(得分:0)
我认为每单位工作一次交易的解决方案限制性太强。在某些环境中,人们可能需要能够在每个会话中执行多个事务。我自己明确管理交易,似乎是一个灵活的解决方案。
public interface IUnitOfWork: IDisposable
{
IGenericTransaction BeginTransaction();
}
public interface IGenericTransaction: IDisposable
{
void Commit();
void Rollback();
}
public class NhUnitOfWork: IUnitOfWork
{
private readonly ISession _session;
public ISession Session
{
get { return _session; }
}
public NhUnitOfWork(ISession session)
{
_session = session;
}
public IGenericTransaction BeginTransaction()
{
return new NhTransaction(_session.BeginTransaction());
}
public void Dispose()
{
_session.Dispose();
}
}
public class NhTransaction: IGenericTransaction
{
private readonly ITransaction _transaction;
public NhTransaction(ITransaction transaction)
{
_transaction = transaction;
}
public void Commit()
{
_transaction.Commit();
}
public void Rollback()
{
_transaction.Rollback();
}
public void Dispose()
{
_transaction.Dispose();
}
}
用法如下所示。它很容易融入任何模式。
public void Do(IUnitOfWork uow)
{
using (var tx = uow.BeginTransaction()) {
// DAL calls
tx.Commit();
}
}