NHibernate的Session管理策略和NHibernateHelper

声明

本篇中提到的Session,并非是Asp.NET中的Session,而是NHibernate中ISession。

本篇假设读者已经对NHibernate的有一定的了解,已经成功持久化过领域模型。

你不需要亲自用复制本篇的代码去调试,因为本篇的代码并不全,最后也有提供下载。

本篇中的单元测试用到了NUnit,如果你使用其他框架也并不影响理解。

 

正文 开门见山

在ASP.NET中,如果我们希望每一个HTTP的请求只打开一个Session,在请求结束时关闭这个Session。

也就是在请求期间,只用到这一个Session。或许我们可以称他为“one session per request”。

这样做得好处是,你可以更容易地使用延迟加载,因为当领域模型传到表示层时,ISession在表示层仍然是打开的,并再请求结束后自动销毁。

另外在单元测试时,并不一定有HTTP的请求,所以需要用另一种策略代替。

 

作法:

我们会在ASP.NET应用程序中这样使用

HttpContext context = HttpContext.Current;
if (context.Items["nhsession"] == null)
{
        context.Items["nhsession"] = sessionFactory.OpenSession();
}
return context.Items["nhsession"] as ISession;


以上代码意思是:我们需要Session时,就从web的上下文中取,一个请求中第一次会打开一个Session并保存再web上下文,以后就不再新打开了。

 

但是有了这样的一个GetSession方法后,并不代表万事大吉了。

下面来看一下单元测试:

[Test]
public void GetSessionTest()
{
    ISession session=  NHibernateHelper.GetSession();
}

报错了,未将对象引用到实例,是哪个对象呢?HttpContext.Currtent为null。

因为建立的是类库,这里并没有web的上下文。那怎么办呢?

所以在这里我使用两套Session策略

1、在Web应用程序中,就使用刚才提到的策略。

2、在WinForm或单元测试中,使用另一种策略,每个线程用一个Session。

 

其实在NHibernate文档中也有提到,在1.2以后的版本中,增加了一个GetCurrentSession()的方法,用于获取当前Session,这个上下文只支持一个ISessionFactory。你必须自己通过CurrentSessionContext类中的静态方法手动的把ISession实例绑定或者取消绑定到当前上下文。

修改代码

        private static void BindContext()
        {
            if (!CurrentSessionContext.HasBind(sessionFactory))
            {
                CurrentSessionContext.Bind(sessionFactory.OpenSession());
            }
        }

        private static void UnBindContext()
        {
            if (CurrentSessionContext.HasBind(sessionFactory))
            {
                CurrentSessionContext.Unbind(sessionFactory);
            }
        }

        public static ISession GetCurrentSession()
        {
            BindContext();
            return sessionFactory.GetCurrentSession();
        } 


这样做可以避免在代码中自己实现策略模式与IOC,NHibernate已经帮我们做好了。

修改hibernate.cfg.xml配置文件,加入一个属性<property name="current_session_context_class">web</property>,修改这个属性就可以修改Session策略。

也可以定义在代码中。

sessionFactory = new Configuration().Configure()
                .SetProperty("current_session_context_class", currentSessionContextClass.ToString())
                .BuildSessionFactory();



    /// <summary>
    /// 当前Session上下文模式
    /// 特定环境下,当前Session保存在特定的上下文中
    /// </summary>
    public enum CurrentSessionContextClass
    {
        managed_web,
        call,
        thread_static,
        web
    }


现在,我们就可以在web应用程序中将参数设置为web,而单元测试中将参数设置为thread_static。

        void Application_Start(object sender, EventArgs e)
        {
            // 在应用程序启动时运行的代码
            NHibernateHelper.Instance(CurrentSessionContextClass.web);
        }

 

        ISession session;
        [SetUp]
        public void Setup()
        {
            NHibernateHelper.Instance(CurrentSessionContextClass.thread_static);
            session = NHibernateHelper.GetCurrentSession();
        }

 

下载:

 最后分享一个相关的NHibernateHelper文件

posted @ 2013-05-17 13:59  十三燕  阅读(8171)  评论(2编辑  收藏  举报