摘要
NHibernate的Session的管理涉及到NHibernate的两个最重要的对象ISessionFactory和ISession。ISessionFactory的生成非常消耗资源,通常都在应用程序启动的时候生成,并使用单例模式,被应用程序的所有线程共享。ISession的生成虽然没有ISessionFactory那么消耗资源,但是Session中保存了一级缓存池,如果每次使用到ISession的时候都生成新的ISession对象,而且这样的操作频率很大的时候,也会一定程度上大量消耗内存资源。NHibernate提供CurrentSessionContext对象,将ISession与当前应用的上下文环境进行绑定,先生成ISession,并与CurrentSessionContext绑定,后面直接从CurrentSessionContext中取ISession,可以显著提高执行效率。
本篇文章全部代码可以到NHibernate Demo下载。
1. ISession管理过程
1)使用单例模式生成ISessionFactory对象。
2)在生成ISessionFactory对象的过程中,使用Configuration对象的CurrentSessionContext()方法,生成CurrentSessionContext。
CurrentSessionContext方法原型:
public static Configuration CurrentSessionContext<TCurrentSessionContext>(this Configuration configuration) where TCurrentSessionContext : ICurrentSessionContext;
TCurrentSessionContext是泛型参数,必须继承ICurrentSessionContext接口。
ICurrentSessionContext接口有两个继承类:WebSessionContext和ThreadStaticSessionContext。在ASP.Net Web程序中使用WebSessionContext类,在Windows Form和控制台应用程序中使用ThreadStaticSessionContext。
3)通过ISessionFactory对象的ISessionFactory.OpenSession()方法生成ISession对象。
4)CurrentSessionContext类提供三个静态方法,Bind/UnBind/HasBind,用来管理CurrentSessionContext对象和ISession对象之间的关系。
下面是这三个方法的原型:
public static void Bind(ISession session);
public static ISession Unbind(ISessionFactory factory);
public static bool HasBind(ISessionFactory factory);
5)如果之前调用了Bind静态方法将ISession对象跟CurrentSessionContext进行绑定,那么调用HasBind方法返回true。此时可以使用ISessionFactory对象的GetCurrentSession方法,获得之前与CurrentSessionContext绑定的ISession对象。
6)ISesion对象用完后,需要调用CurrentSessionContext.Unbind静态方法将当前ISession与当前上下文环境解除绑定。并调用ISession对象的Close()方法关闭ISession对象。
下面是一个完整的ISessionFactory和ISession管理的类。
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Context;
using System;
using System.Web; namespace Demo.Service
{
/// <summary>
/// Manages the NHibernate session
/// </summary>
public class SessionManager
{
private static ISessionFactory SessionFactory { get; set; } public static string ConnectionString { get; set; } private static ISessionFactory GetFactory<T>() where T : ICurrentSessionContext
{
var cfg = new Configuration(); cfg.DataBaseIntegration(x => {
#if DEBUG
x.LogSqlInConsole = true;
#endif
if (!string.IsNullOrEmpty(ConnectionString)
&& ConnectionString.Trim() != "")
{
x.ConnectionString = ConnectionString;
}
}); cfg.Configure().CurrentSessionContext<T>();
return cfg.BuildSessionFactory();
} /// <summary>
/// Gets the current session.
/// </summary>
public static ISession GetCurrentSession()
{
if (SessionFactory == null)
{
SessionFactory = HttpContext.Current != null ? GetFactory<WebSessionContext>() : GetFactory<ThreadStaticSessionContext>();
} if (CurrentSessionContext.HasBind(SessionFactory))
{
return SessionFactory.GetCurrentSession();
} var session = SessionFactory.OpenSession();
CurrentSessionContext.Bind(session); return session;
} /// <summary>
/// Closes the session.
/// </summary>
public static void CloseSession()
{
if (SessionFactory != null && CurrentSessionContext.HasBind(SessionFactory))
{
var session = CurrentSessionContext.Unbind(SessionFactory);
if (session != null && session.IsOpen)
{
session.Close();
}
}
}
2. 在Asp.Net程序中管理ISession对象
Asp.Net的页面请求过程是无状态的,不能将ISession对象持久化到内存中。但是可以使用自定义的IHttpModule对象来实现:每生成一个HTTP请求,生成一个ISession。
public class SessionModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.EndRequest += (sender, e) => SessionManager.CloseSession();
} public void Dispose()
{
}
}
HttpApplication.EndRequest事件在每次HttpRequest执行完毕之后调用,定义此事件用来关闭ISession对象。
在web.config文件中,添加HttpModule。
<system.webServer>
<modules>
<add name="SessionModule" type="Demo.Service.Infrastructure.SessionModule,Demo.Service"/>
</modules>
</system.webServer>
type的值由逗号隔开为两部分,前面部分是Module类的完整类名,后面部分是Module类所在的程序集名称。
3. 数据操作基础类的接口的实现
定义IService<T>接口。T是泛型参数,代表NHibernate映射类,必须是引用类型,因此添加where的class条件。
using System.Collections.Generic;
using System.Linq; namespace Demo.Service.Infrastructure.Interface
{
public interface IService<T> where T : class
{
IList<T> GetAll();
IQueryable<T> Query();
T GetById(int id);
T LoadById(int id);
int Save(T obj, bool includeInTransaction = false);
void Update(T obj, bool includeInTransaction = false);
void Delete(int id, bool includeInTransaction = false);
}
}
定义实现类Service<T>
using Demo.Service.Infrastructure.Interface;
using NHibernate;
using NHibernate.Linq;
using System;
using System.Collections.Generic;
using System.Linq; namespace Demo.Service.Infrastructure
{
public class Service<T> : IService<T> where T : class
{
protected ISession Session
{
get { return SessionManager.GetCurrentSession(); }
} public IList<T> GetAll()
{
IList<T> list = Session.CreateCriteria<T>().List<T>();
return list;
} public virtual IQueryable<T> Query()
{
var result = Session.Query<T>();
return result;
} public T GetById(int id)
{
T obj = Session.Get<T>(id);
return obj;
} public T LoadById(int id)
{
T obj = Session.Load<T>(id);
return obj;
} public int Save(T obj, bool includeInTransaction = false)
{
var identifier = Session.Save(obj);
if (!includeInTransaction)
{
Session.Flush();
}
return Convert.ToInt32(identifier);
} public void Update(T obj, bool includeInTransaction = false)
{
Session.SaveOrUpdate(obj);
if (!includeInTransaction)
{
Session.Flush();
}
} public void Delete(int id, bool includeInTransaction = false)
{
var obj = Session.Get<T>(id);
Session.Delete(obj);
if (!includeInTransaction)
{
Session.Flush();
}
}
}
}
在Insert/Update/Delete方法中添加includeInTransaction参数,如果是从存储过程调用,则传入true,否则用默认值false(立即写入数据库)。
结语
这篇文章介绍了NHibernate的ISessionFactory和ISession的管理方法,ISessionFactory使用单例模式进行创建和管理,ISession的管理基于NHibernate的内置CurrentSessionContext对象,使用该类的静态方法Bind、UnBind和HasBind方法进行ISession的管理。在Asp.Net工程和Windows Form工程中管理ISession的方法是不同的。介绍了在Asp.Net中如何通过自定义HttpModule实现ISession的管理,实现一个请求一个ISession。
下一篇文章开始介绍NHibernate的关系映射。