NHibernate事务。提交自动关闭会话

NHibernate事务。提交自动关闭会话,nhibernate,session,transactions,Nhibernate,Session,Transactions,我有一个web应用程序,它使用的是绝对最新版本(3.3),并且在HttpModule中使用逐请求会话管理,因此没有多个会话冲突的问题。不幸的是,我发现会话在我执行Transaction.Commit后立即自动关闭,而我只有在实际执行创建、更新或删除操作时才会这样做。我在我的NHibernate日志中找到了这个 我知道我没有这样做,因为对ISession.Close函数的唯一调用是在我的HttpModule中完成的 是的,当然我可以在SessionManager中放入代码来检查IsClosed参数

我有一个web应用程序,它使用的是绝对最新版本(3.3),并且在HttpModule中使用逐请求会话管理,因此没有多个会话冲突的问题。不幸的是,我发现会话在我执行Transaction.Commit后立即自动关闭,而我只有在实际执行创建、更新或删除操作时才会这样做。我在我的NHibernate日志中找到了这个

我知道我没有这样做,因为对ISession.Close函数的唯一调用是在我的HttpModule中完成的

是的,当然我可以在SessionManager中放入代码来检查IsClosed参数,然后使用OpenSession函数而不是GetCurrentSession,但这是否应该发生呢?是否有某种方法可以通过我的配置或我可以在会话或事务对象上设置的某些属性来防止这种情况发生,或者这只是我在任何地方都找不到任何文档的新特性之一

请帮忙

布莱恩

我被要求提供一些代码,下面是HttpModule的代码:

public class NhibernateModule : IHttpModule
{
    public void Dispose()
    {
    }

    public void Init(HttpApplication context)
    {
        context.BeginRequest += new EventHandler(context_BeginRequest);
        context.EndRequest += new EventHandler(context_EndRequest);
    }

    public void context_BeginRequest(Object sender, EventArgs e)
    {
        WebSessionContext.Bind(NhibernateSessionManager.GetContextSession());
    }

    public void context_EndRequest(Object sender, EventArgs e)
    {
        ISession session = WebSessionContext.Unbind(NhibernateSessionManager.SessionFactory);

        if (session != null)
        {
            if (session.Transaction != null && session.Transaction.IsActive)
            {
                session.Transaction.Rollback();
            }
            else
                session.Flush();

            session.Close();
        }
    }
}
}

接下来,您将找到我在SessionManager中使用的原始代码:

public sealed class NhibernateSessionManager
{
    private readonly ISessionFactory sessionFactory;
    public static ISessionFactory SessionFactory
    {
        get { return Instance.sessionFactory; }
    }

    private ISessionFactory GetSessionFactory()
    {
        return sessionFactory;
    }

    public static NhibernateSessionManager Instance
    {
        get { return NestedSessionManager.sessionManager; }
    }

    public static ISession GetContextSession()
    {
        ISession session;
        if (CurrentSessionContext.HasBind(SessionFactory))
        {
            session = SessionFactory.GetCurrentSession();
        }
        else
        {
            session = SessionFactory.OpenSession();
            CurrentSessionContext.Bind(session);
        }
        return session;
    }  

    private NhibernateSessionManager()
    {
        if (sessionFactory == null)
        {
            Configuration configuration;
            configuration = new Configuration().Configure(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "web.config"));
            log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "web.config")));

            //Configuration configuration = new Configuration().Configure();
            if (configuration == null)
            {
                throw new InvalidOperationException("NHibernate configuration is null.");
            }
            else
            {
                sessionFactory = configuration.BuildSessionFactory();
                if (sessionFactory == null)
                    throw new InvalidOperationException("Call to BuildSessionFactory() returned null.");
            }
        }
    }

    class NestedSessionManager
    {
        internal static readonly NhibernateSessionManager sessionManager = new NhibernateSessionManager();
    }
}
最后,这里是一个函数,它当前正在导致会话在事务完成后立即关闭。Commit()。每个内部函数检索当前会话,然后处理一个保存调用

    public static Int32 AddVideo(VideoFile Video, Int32 UserID, Int16 InstID)
    {
        log.Debug("Begin AddVideo");
        Int32 FileID = 0;

        using (ISession Session = NhibernateSessionManager.GetContextSession())
        {
            using (ITransaction Transaction = Session.BeginTransaction())
            {
                Video.Created = DateTime.Now;
                Video.Modified = DateTime.Now;

                FileID = (Int32)Session.Save(Video);
                Video.FileID = FileID;

                // Need to process through all the categories and insert records into the ivxFileCategories table
                // to associate the newly created file with the chosen categories
                if (Video.CategoryAssociations != null)
                {
                    log.Info("Number of categories to be associated with the video: " + Video.CategoryAssociations.Count);
                    for (int i = 0; i < Video.CategoryAssociations.Count; i++)
                    {
                        CategoryFileAssociation Assoc = (CategoryFileAssociation)Video.CategoryAssociations[i];
                        Assoc.FileID = FileID;
                        AssociationManager.AddCategoryFileTransaction(Assoc);
                    }
                }

                // Need to add the default file access for the UserDetail that is creating the new video which will always
                // be Admin because the UserDetail creating a file should always have admin access over the file, no matter
                // what their default role is.
                AssociationManager.AddFileAccessTransaction(FileID, UserID, UserClassConstants.IVXUSERCLASS_ADMIN);

                // Need to add the institutional association based on whether the new video was created by a librarian
                // or one of the iVidix admins
                AssociationManager.AddInstitutionFileTransaction(InstID, FileID);

                Transaction.Commit();
            }
        }

        log.Debug("End AddVideo");
        return FileID;
    }
public static Int32 AddVideo(视频文件视频,Int32用户ID,Int16 institd)
{
调试(“开始添加视频”);
Int32 FileID=0;
使用(ISession Session=NhibernateSessionManager.GetContextSession())
{
使用(ITransaction Transaction=Session.BeginTransaction())
{
Video.Created=DateTime.Now;
Video.Modified=DateTime.Now;
FileID=(Int32)Session.Save(视频);
Video.FileID=FileID;
//需要处理所有类别并将记录插入ivxFileCategories表
//将新创建的文件与所选类别关联
if(Video.categoryasociations!=null)
{
log.Info(“与视频关联的类别数:“+video.categoryasociations.Count”);
对于(int i=0;i
会话将在AddVideo方法中释放,因为您正在为会话使用

using (ISession Session = NhibernateSessionManager.GetContextSession())
{

}

会话将在AddVideo方法中释放,因为您正在为会话使用

using (ISession Session = NhibernateSessionManager.GetContextSession())
{

}

我完全建议将交易内容剥离

using (ISession Session = NhibernateSessionManager.GetContextSession())
{
  using (ITransaction Transaction = Session.BeginTransaction())
  {
   ...
  }
}
并将其移动到开始/结束请求中。这样,每个请求都有一个UOW
。会话关闭的原因是由于
using语句

您的begin请求代码可以是以下代码:-

var session = sessionFactory.OpenSession();
CurrentSessionContext.Bind(session);
session.BeginTransaction();
你的最终要求是:-

var session = CurrentSessionContext.Unbind(sessionFactory);

if (session != null)
{
    if (session.Transaction.IsActive)
    {
        try
        {
            session.Transaction.Commit();
        }
        catch
        {
            session.Transaction.Rollback();
        }
    }
    session.Close();
}
我的global.asax中有这个

public static ISessionFactory SessionFactory { get; set; }
这在我的存储库中

    public ISession Session
    {
        get
        {
            return SessionFactory.GetCurrentSession();
        }
    }

现在,我使用IOC将sessionFactory传递到我的存储库层,否则您需要自己手动传递。

我完全建议剥离事务内容

using (ISession Session = NhibernateSessionManager.GetContextSession())
{
  using (ITransaction Transaction = Session.BeginTransaction())
  {
   ...
  }
}
并将其移动到开始/结束请求中。这样,每个请求都有一个UOW
。会话关闭的原因是由于
using语句

您的begin请求代码可以是以下代码:-

var session = sessionFactory.OpenSession();
CurrentSessionContext.Bind(session);
session.BeginTransaction();
你的最终要求是:-

var session = CurrentSessionContext.Unbind(sessionFactory);

if (session != null)
{
    if (session.Transaction.IsActive)
    {
        try
        {
            session.Transaction.Commit();
        }
        catch
        {
            session.Transaction.Rollback();
        }
    }
    session.Close();
}
我的global.asax中有这个

public static ISessionFactory SessionFactory { get; set; }
这在我的存储库中

    public ISession Session
    {
        get
        {
            return SessionFactory.GetCurrentSession();
        }
    }

现在我使用IOC将sessionFactory传递到我的存储库层,否则您需要自己手动传递。

提交事务将结束该会话

将事务开始移动到上下文\u BeginRequest和上下文中的提交/清理\u EndRequest


实际上,我不喜欢视图模式中的会话,更喜欢将事务保持尽可能短的打开状态,而是将会话注入控制器。然后,我在操作或服务中执行事务。我更喜欢这种事务的细粒度控制,并使它们保持短暂的生命,避免任何锁定问题。

提交事务将结束该会话

将事务开始移动到上下文\u BeginRequest和上下文中的提交/清理\u EndRequest


实际上,我不喜欢视图模式中的会话,更喜欢将事务保持尽可能短的打开状态,而是将会话注入控制器。然后,我在操作或服务中执行事务。我更喜欢这种事务的细粒度控制,并使它们保持短暂的生命周期,以避免任何锁定问题。

是否使用嵌套事务?你在什么时候打电话?确认吗?我们可以看到一些保存代码和HttpModu的代码吗