丹尼大叔

数学专业毕业,爱上编程的大叔,兴趣广泛。使用博客园这个平台分享我工作和业余的学习内容,以编程交友。有朋自远方来,不亦乐乎。

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

摘要

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的关系映射。

posted on 2016-07-09 16:08  丹尼大叔  阅读(1312)  评论(0编辑  收藏  举报