摘要
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管理的类。
1 using NHibernate; 2 using NHibernate.Cfg; 3 using NHibernate.Context; 4 using System; 5 using System.Web; 6 7 namespace Demo.Service 8 { 9 /// <summary> 10 /// Manages the NHibernate session 11 /// </summary> 12 public class SessionManager 13 { 14 private static ISessionFactory SessionFactory { get; set; } 15 16 public static string ConnectionString { get; set; } 17 18 private static ISessionFactory GetFactory<T>() where T : ICurrentSessionContext 19 { 20 var cfg = new Configuration(); 21 22 cfg.DataBaseIntegration(x => { 23 #if DEBUG 24 x.LogSqlInConsole = true; 25 #endif 26 if (!string.IsNullOrEmpty(ConnectionString) 27 && ConnectionString.Trim() != "") 28 { 29 x.ConnectionString = ConnectionString; 30 } 31 }); 32 33 cfg.Configure().CurrentSessionContext<T>(); 34 return cfg.BuildSessionFactory(); 35 } 36 37 /// <summary> 38 /// Gets the current session. 39 /// </summary> 40 public static ISession GetCurrentSession() 41 { 42 if (SessionFactory == null) 43 { 44 SessionFactory = HttpContext.Current != null ? GetFactory<WebSessionContext>() : GetFactory<ThreadStaticSessionContext>(); 45 } 46 47 if (CurrentSessionContext.HasBind(SessionFactory)) 48 { 49 return SessionFactory.GetCurrentSession(); 50 } 51 52 var session = SessionFactory.OpenSession(); 53 CurrentSessionContext.Bind(session); 54 55 return session; 56 } 57 58 /// <summary> 59 /// Closes the session. 60 /// </summary> 61 public static void CloseSession() 62 { 63 if (SessionFactory != null && CurrentSessionContext.HasBind(SessionFactory)) 64 { 65 var session = CurrentSessionContext.Unbind(SessionFactory); 66 if (session != null && session.IsOpen) 67 { 68 session.Close(); 69 } 70 } 71 }
2. 在Asp.Net程序中管理ISession对象
Asp.Net的页面请求过程是无状态的,不能将ISession对象持久化到内存中。但是可以使用自定义的IHttpModule对象来实现:每生成一个HTTP请求,生成一个ISession。
1 public class SessionModule : IHttpModule 2 { 3 public void Init(HttpApplication context) 4 { 5 context.EndRequest += (sender, e) => SessionManager.CloseSession(); 6 } 7 8 public void Dispose() 9 { 10 } 11 }
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条件。
1 using System.Collections.Generic; 2 using System.Linq; 3 4 namespace Demo.Service.Infrastructure.Interface 5 { 6 public interface IService<T> where T : class 7 { 8 IList<T> GetAll(); 9 IQueryable<T> Query(); 10 T GetById(int id); 11 T LoadById(int id); 12 int Save(T obj, bool includeInTransaction = false); 13 void Update(T obj, bool includeInTransaction = false); 14 void Delete(int id, bool includeInTransaction = false); 15 } 16 }
定义实现类Service<T>
1 using Demo.Service.Infrastructure.Interface; 2 using NHibernate; 3 using NHibernate.Linq; 4 using System; 5 using System.Collections.Generic; 6 using System.Linq; 7 8 namespace Demo.Service.Infrastructure 9 { 10 public class Service<T> : IService<T> where T : class 11 { 12 protected ISession Session 13 { 14 get { return SessionManager.GetCurrentSession(); } 15 } 16 17 public IList<T> GetAll() 18 { 19 IList<T> list = Session.CreateCriteria<T>().List<T>(); 20 return list; 21 } 22 23 public virtual IQueryable<T> Query() 24 { 25 var result = Session.Query<T>(); 26 return result; 27 } 28 29 public T GetById(int id) 30 { 31 T obj = Session.Get<T>(id); 32 return obj; 33 } 34 35 public T LoadById(int id) 36 { 37 T obj = Session.Load<T>(id); 38 return obj; 39 } 40 41 public int Save(T obj, bool includeInTransaction = false) 42 { 43 var identifier = Session.Save(obj); 44 if (!includeInTransaction) 45 { 46 Session.Flush(); 47 } 48 return Convert.ToInt32(identifier); 49 } 50 51 public void Update(T obj, bool includeInTransaction = false) 52 { 53 Session.SaveOrUpdate(obj); 54 if (!includeInTransaction) 55 { 56 Session.Flush(); 57 } 58 } 59 60 public void Delete(int id, bool includeInTransaction = false) 61 { 62 var obj = Session.Get<T>(id); 63 Session.Delete(obj); 64 if (!includeInTransaction) 65 { 66 Session.Flush(); 67 } 68 } 69 } 70 }
在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的关系映射。