NHibernate-在Dispose()方法中使用Session.Flush()-好主意还是坏主意?

NHibernate-在Dispose()方法中使用Session.Flush()-好主意还是坏主意?,nhibernate,transactions,castle-windsor,unit-of-work,Nhibernate,Transactions,Castle Windsor,Unit Of Work,我通过一组接口在应用程序中使用NHibernate。ISession封装在一个名为IUnitOfWork的接口中,其具体实现如下所示: public class UnitOfWork : IUnitOfWork { private ISession _session; public UnitOfWork() { _session = KctcSessionFactory.OpenSession(); } public void Dispose() {

我通过一组接口在应用程序中使用NHibernate。
ISession
封装在一个名为
IUnitOfWork
的接口中,其具体实现如下所示:

public class UnitOfWork : IUnitOfWork
{
  private ISession _session;

  public UnitOfWork()
  {
    _session = KctcSessionFactory.OpenSession();
  }

  public void Dispose()
  {
    try
    {
      _session.BeginTransaction();
      _session.Flush();
      _session.Transaction.Commit();
    }
    catch (Exception)
    {
      _session.Transaction.Rollback();
      _session.Transaction.Dispose();
      throw;
    }
  }

  public T Load<T>(int id)
  {
    return _session.Load<T>(id);
  }

  public IQueryable<T> GetList<T>()
  {
    return _session.Linq<T>();
  }

  public void Save(object entity)
  {
    _session.SaveOrUpdate(entity);
  }

  public void Delete(object entity)
  {
    _session.Delete(entity);
  }
}
public class UnitOfWork : IDisposable
{
    ISession currentSession;
    bool shouldCommit;

    public UnitOfWork()
    {
        currentSession = KctcSessionFactory.OpenSession();
        currentSession.BeginTransaction();
    }

    public void Commit()
    {
        shouldCommit = true;
    }

    public void Dispose()
    {
        if (shouldCommit)
        {
            currentSession.Transaction.Commit();
        }
        else
        {
            currentSession.Transaction.Rollback();
        }

        currentSession.Dispose();
    }
}
公共类UnitOfWork:IUnitOfWork
{
非公开会议;
公共工作单元()
{
_session=KctcSessionFactory.OpenSession();
}
公共空间处置()
{
尝试
{
_session.BeginTransaction();
_session.Flush();
_Commit();
}
捕获(例外)
{
_session.Transaction.Rollback();
_session.Transaction.Dispose();
投掷;
}
}
公共T负载(内部id)
{
返回会话加载(id);
}
公共IQueryable GetList()
{
return_session.Linq();
}
公共作废保存(对象实体)
{
_会话。保存或更新(实体);
}
公共作废删除(对象实体)
{
_删除(实体);
}
}
IUnitOfWork
由castle windsor处理,其生活方式是
PerWebRequest
。这意味着从web请求的角度来看,
IUnitOfWork
实际上是一个单例,并在请求结束时自动处理

这个代码在我看来完全是万无一失的。当在web请求结束时处理
IUnitOfWork
时,所有保存的实体都将被刷新,并且整个操作都包装在一个事务中,因此它是以原子方式完成的。我不需要在这个类之外使用事务。我说得对吗?这个密码安全吗?还是我错过了什么可怕的事情


为清晰起见进行了编辑:我想知道我是否正确地假设所有刷新/提交到数据库的操作都将等待会话被释放,因此可以在
Dispose
方法中包装到单个事务中。或者,在我使用
Dispose
方法显式处理数据之前,是否存在数据可能被刷新的情况?或者出于其他原因我可能需要显式使用事务?

提交事务将自动刷新会话,因此不需要。我不会将Load和GetList方法放在一个工作单元中,因为这是存储库或DAO更关心的问题。否则对我来说没问题。

我发现您使用NHibernate的方式存在一些问题

1) 如果您使用的是带有默认设置的NHibernate,那么它将以刷新模式自动运行,这意味着在执行查询时,更改有时会刷新到数据库中,以避免过时的结果。这可能意味着,在您的事务之外,这些内容将被过早地刷新

2) 当您的事务仅跨越刷新操作时,读取发生在事务外部,并且不受与事务相同的隔离级别的约束。为了使事务真正原子化和隔离,您需要在创建会话后立即启动事务

更好的uow应该是这样的:

public class UnitOfWork : IUnitOfWork
{
  private ISession _session;

  public UnitOfWork()
  {
    _session = KctcSessionFactory.OpenSession();
  }

  public void Dispose()
  {
    try
    {
      _session.BeginTransaction();
      _session.Flush();
      _session.Transaction.Commit();
    }
    catch (Exception)
    {
      _session.Transaction.Rollback();
      _session.Transaction.Dispose();
      throw;
    }
  }

  public T Load<T>(int id)
  {
    return _session.Load<T>(id);
  }

  public IQueryable<T> GetList<T>()
  {
    return _session.Linq<T>();
  }

  public void Save(object entity)
  {
    _session.SaveOrUpdate(entity);
  }

  public void Delete(object entity)
  {
    _session.Delete(entity);
  }
}
public class UnitOfWork : IDisposable
{
    ISession currentSession;
    bool shouldCommit;

    public UnitOfWork()
    {
        currentSession = KctcSessionFactory.OpenSession();
        currentSession.BeginTransaction();
    }

    public void Commit()
    {
        shouldCommit = true;
    }

    public void Dispose()
    {
        if (shouldCommit)
        {
            currentSession.Transaction.Commit();
        }
        else
        {
            currentSession.Transaction.Rollback();
        }

        currentSession.Dispose();
    }
}
允许使用需要检查web请求是否成功且无异常的场景,如果是这种情况,则在当前uow上调用
Commit


这有道理吗?

哎呀!当我可以提交事务时,我才意识到我不需要_session.Flush()。顺便说一句,这不是生产代码。谢谢。回复:加载和获取列表。我所有的数据访问都是通过repositories完成的,但存储库反过来调用IUnitOfWork的方法。这是因为在NHibernate中,这个功能是通过ISession访问的,正如您在代码中看到的那样。@David,是的,我理解您的设计。我想说的是,这不是最优的。我将遵循关注点分离的原则。工作单元应负责启动事务,并在完成时提交和处理会话。您的存储库应该关注CRUD。没有什么能阻止您使用NHibernate会话注入这两种方法,并将它们用于不同的事情。你只需要确保配置你的IOC容器,将它们注入会话的同一个实例。哦,我明白了,谢谢你的澄清。关于工作单位的职责应该是什么,我想你比我有一个更清晰的想法。我对一个工作单元所做工作的概念基本上来自于这样一个想法,即ISession本身就是一个工作单元实现。我从来没有想到ISession本身有更广泛的责任。@David,我没有注意到你实际上只是为了冲销而开始交易@mookid8000对工作单元的实施情况良好。工作单元管理会话,而存储库执行crud交互。您不需要将crud交互打包到另一个层中。谢谢。这帮了大忙。确保例外情况阻止UOW进入应该不是特别困难。IOC容器,因此UOW,对于任何异常处理代码都是可见的。但是您提醒我,这么晚才将ISession留给DB可能并不可取。例如,我可能需要先知道刷新是否成功,然后再执行其他操作,例如发送确认电子邮件。这里我有很多要考虑的。一般来说,我会建议在某种消息传递基础设施之后与外部系统(如发送邮件)解耦集成。如果为此使用MSMQ,例如通过使用NServiceBus,您可以让消息传递和db操作参与同一事务,从而允许
SendMail
消息传递事务与数据库事务一起回滚。