C# 在nhibernate中的一个会话中是否可以发生多个事务?这是个坏主意吗?

C# 在nhibernate中的一个会话中是否可以发生多个事务?这是个坏主意吗?,c#,nhibernate,transactions,unit-of-work,C#,Nhibernate,Transactions,Unit Of Work,我正在考虑为NHibernate持久层创建自己的IUnitOfWork实现 似乎正确的方法是在构造函数中实例化ISession和ITransaction,然后在析构函数或Dispose()方法中进行处理 当然,如果有人调用Save()方法,那么ISession将被刷新,ITransaction将完成,因此在调用Save()之后,将不会有一个有效的打开事务再次进入Save()。。。除非我提交了第一笔交易并立即打开了另一笔新交易。但这是个好主意吗 就设计而言,执行一个提交操作是有意义的,但我不一定能

我正在考虑为NHibernate持久层创建自己的
IUnitOfWork
实现

似乎正确的方法是在构造函数中实例化
ISession
ITransaction
,然后在析构函数或
Dispose()
方法中进行处理

当然,如果有人调用
Save()
方法,那么
ISession
将被刷新,
ITransaction
将完成,因此在调用
Save()
之后,将不会有一个有效的打开事务再次进入
Save()
。。。除非我提交了第一笔交易并立即打开了另一笔新交易。但这是个好主意吗

就设计而言,执行一个提交操作是有意义的,但我不一定能控制代码,其他开发人员可能对遵循UnitOfWork模式的纪律性较低


通过尝试使UnitOfWork对每个会话的多个事务具有容错性,我是否会有所损失/收获?我是否应该检查一个打开的事务并在它已经提交时抛出一个异常,而不是创建一个新的事务?

有多个选项可以使用工作单元实现nhibernate嵌套事务

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();
    }
}
这里我使用命令模式作为工作单元

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();
    }
}
公共接口接口接口
{    
void Execute();
}
公共抽象集体诉讼:IAction,IDisposable,其中T:Action
{
public void Execute()
{
尝试
{
//根据您的工作单元模式或
transaction.Begin();
OnExecute();
//结束工作单位
Commit();
}
捕获(例外e)
{
transaction.Rollback();
投掷e;
}
}
受保护的抽象void OnExecute();
公共空间处置()
{
}
}
公共类MyBusinessLogic:操作
{
受保护的覆盖void OnExecute()
{
//实施
}
}
公共类MyAnotherBusinessLogic:行动
{
受保护的覆盖void OnExecute()
{
//嵌套事务
MyBusinessLogic逻辑=新的MyBusinessLogic();
logic.Execute();
}
}

我认为每个工作单元有一个事务的解决方案限制太多。在某些环境中,每个会话可能需要执行多个事务的能力。我自己明确地管理事务,这似乎是一个灵活的解决方案

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();
  }
}

回答第一个问题:是的,一个会话中可能有多个事务

这是个好主意吗?视情况而定

问题是第一个事务中更改的数据将被提交,而不确定整个工作单元(会话)是否在最后提交。比如说,当您在以后的事务中收到StaleObjectException时,您已经提交了一些数据。请注意,这种异常会使会话无法使用,因此您必须销毁它。那就很难重新开始,再试一次

我要说的是,在这种情况下,它运行良好:

  • 它是一个UI应用程序
  • 更改仅在最后一个事务中刷新
用户界面应用程序

错误由用户交互处理。这意味着用户可以看到错误情况下实际存储的内容,并重复所做的更改

更改仅在最后一个事务中刷新

NH实现的会话仅在结尾或“必要时”刷新更改。因此,在提交会话之前,可以将更改保留在内存中。问题是NH需要在每次查询之前刷新会话,这很难控制。它可以关闭,这会导致副作用。在编写简单事务时,您可以控制它。在一个复杂的系统中,几乎不可能确保没有任何问题

简单方法(tm)

我编写了一个相当大的客户机-服务器系统的持久层。在这样的系统中,您不需要用户直接处理错误。您需要处理系统中的错误,并以一致的状态将控制权返回给客户端


我将整个事务处理简化到绝对最小,以使其稳定和“防白痴”。我总是同时创建一个会话和一个事务,它要么提交,要么不提交。

它是为web应用程序设计的。我的理解是,
ITransaction.Commit()
调用将刷新会话。使用同一会话实例化新的
ITransaction
,紧接着
Commit()
,什么情况会生成
StaleObjectException
?提交事务会释放锁。这使得它更有可能获得StaleObjectException。但无论如何都可以得到它们,因为在内存中更改数据时,数据可以在数据库中更改。NH的乐观锁定至少可以检测到这些冲突。感谢您提供的详细答案。只需指出几件事:1)已经有了一个系统。操作将使名称变得混乱。2) Action类没有定义事务的来源。3) 这仍然会导致与NHibernate中嵌套事务相同的错误(提交内部事务将使外部事务抛出ObjectDisposedException)。这正是我们所做的,但在这种情况下不起作用:我想无法在注释中进行代码编辑。。。但是如果你有另一个事务在里面,它就不起作用了。但它应该这样做。嵌套事务在数据库中实现是有充分理由的。