NHibernate中的工作单元和每个请求的会话

Tyl*_*ght 1 c# nhibernate unit-of-work session-per-request

我想我的工作单元可能会在我的架构中设置错误.这是我目前拥有的(缩进显示顺序):

HttpRequest.Begin()
  UnitOfWork.Begin()
    Session.BeginTransaction(System.Data.IsolationLevel.ReadCommitted);
Run Code Online (Sandbox Code Playgroud)

在这里,我使用NHibernate调用各种服务来执行crud.当我想对数据库进行更改(更新/保存)时,我调用此代码:

        using (var transaction = unitOfWork.Session.BeginTransaction())
        {
            try
            {
                // These are just generics
                ret = (Key)unitOfWork.Session.Save(entity);
                transaction.Commit();
                rb.unitOfWork.Session.Clear();
            }
            catch
            {
                transaction.Rollback();
                rb.unitOfWork.Session.Clear();
                rb.unitOfWork.DiscardSession();
                throw;
            }
        }
Run Code Online (Sandbox Code Playgroud)

当HttpRequest结束时,我执行以下步骤:

      UnitOfWork.Commit()
    Transaction.Commit() // This is my sessions transaction from the begin above
Run Code Online (Sandbox Code Playgroud)

我遇到了能够回滚大批量进程的问题.因为我在我的CRUD层中提交我的事务,如上所示,我的事务不再处于活动状态,当我尝试在UnitOfWork中回滚时,由于事务已经提交,它什么都不做.我在我的CRUD层中提交代码的原因是我可以尽可能快地保留我的数据,而不会长时间锁定数据库.

在上述情况下采取的最佳行动方案是什么?我是否只进行了不提交批处理作业的特殊CRUD操作,只是在我的工作结束时处理提交,或者我的逻辑是否与我的UnitOfWork和Session Per Request有关?有什么建议?

Ran*_*den 8

您已经发现了每个请求会话模式如此受欢迎的原因以及可能源于对您的工作单元进行微观管理的问题.

通常,对于每个Web请求,在该请求中需要完成的所有操作都可以被视为一个工作单元,因此您可以在该单个Web请求期间只打开一个工作单元和一个NHibernate会话.

此外,我认为你可能对NHibernate如何工作有点困惑,因为你的问题中的这句话:"我在CRUD层提交代码的原因是我可以尽快保存我的数据而不锁定数据库时间过长."

NHibernate不会导致数据库中的任何锁定.每次调用ISession.Save(实体)时,只要不调用ISession.Flush()或ITransaction.Commit(),就不会将任何内容写入数据库,而是将其添加到要插入的项目队列或在Web请求结束时提交当前事务时在数据库中更新.

因此,每个请求的会话应该如下设置:

void Application_BeginRequest()
{
    // Start your unit of work, open a session and begin a transaction
}

// Do all of your work ( Read, insert, update, delete )

void Application_EndRequest()
{
    try
    {
        // UnitOfWork.Current.Transaction.Commit();
    }
    catch( Exception e )
    {
        // UnitOfWork.Current.Transaction.Rollback();
    }
}
Run Code Online (Sandbox Code Playgroud)

当然,有很多方法可以做同样的事情,但这是每个请求模式的会话的基础 - 只有一个会话用于整个Web请求.