一步步学习NHibernate(6)——ISession的管理
请注明转载地址:http://www.cnblogs.com/arhat
今天老魏那个汗啊,我的ThinkPad的电源线不通电了,擦啊。明天还得掏银子买一个!心疼啊,原装的啊。不过话说回来,已经用了将近10年了,已经算是可以的的了。不过就是心疼啊!明天还得给我的Thinkpad找个小三,哎!
通过前面两章的学习,我们知道了爱NHibernate中的核心技术就是懒加载,这个懒加载技术主要作用于有关系的表中,比如多对一,一对多。通过懒加载技术,我们可以很容易的获得关联的数据,但是懒加载却是有一个缺点的,我们拿前面的例子来说,如果现在我们要获得一个班级中所有的学生信息,当学生表中的数据不是很多的情况下,那么还不怎么影响效率的,如果是1000条,但是我们只需要其中的两条,那么NHiberante不会非常智能的加载出来,而是把1000条数据全部加载进来,很显然这不是我们想要的结果了。
如何解决这问题呢,我们在后面的HQL中来解决这个问题,本章呢,主要和大家来讨论一下对NHibernate的ISession管理。由于在NHibernate中,ISessionFactory是一个重量级对象,不能用一次创建一次,而是要在整个应用程序中只创建一次,而ISession是一个轻量级的对象,但是确是线程不安全的,所以我们今天要讨论的问题就是如何来管理他们。
首先我们来先分析一下原来写的NHibernateHelper.cs
public static class NHibernateHelper
{
private static ISessionFactory factory = null;
static NHibernateHelper()
{
factory = new Configuration().Configure().BuildSessionFactory();
}
public static ISession OpenSession()
{
return factory.OpenSession();
}
}
}
在这个类中,我们把ISessionFactory定义成一个私有的静态变量,由于ISessionFactory是一个重量级对象,那么我们不能每次都要创建,这样浪费我们系统的资源的。所以,我们把它定义为一个静态的变量(当然,也可以使用单态来写)。然后我们在静态构造函数中通过Configuration读取配置文件并创建ISessionFactory对象,那么当程序运行的时候在内存中只有一个ISessionFactory对象了。
接着,我们写了一个静态的方法,这个方法用来得到一个ISession对象用来和数据库打交道。但是这里需要说明的是当每一次调用OpenSession这个方法的时候,ISessionFactory都会创建一个全新的ISession对象。当然提出这个问题并不是说这样不好,而是这样创建出来的ISession对象是无法控制业务逻辑中的事务的(下面将会提到)。首先我们来测试一下通过OpenSession创建出来的ISession对象是不是全新的。
我们在主程序中写一个测试的方法:
static void Main(string[] args)
{
NHibernate.ISession session1 = DAL.NHibernateHelper.OpenSession();
NHibernate.ISession session2 = DAL.NHibernateHelper.OpenSession();
Console.WriteLine(session1 == session2);
}

从上面打印出的结果,我们可以看出通过OpenSession来创建的ISession对象都是全新的。那么这样的话会产生一个非常严重的问题,就是上面老魏说的如果我们在一次业务逻辑中同时执行了多个数据库操作,而每一次都需要打开一个ISession,那么事务是无法控制这些操作的。尤其在Web开发中,我们很有可能在一次请求过程中,执行了多次数据库操作,而却只需要一个事务提交,那么OpensSession是无法达到我们的要求的。所以NHibenrate为我们提供了一个新的方法用来创建ISession,这个方法就是GetCurrentSession。通过这个方法创建的ISession的生命周期是在一个上下文中,也就是说这个方法创建的ISession和当前线程以及当前请求时绑定在一起的,只要线程和请求没有被释放,那么着整个执行期间都是用这一个ISession。那么很显然,GetCurrentSession正是我们需要的。
那么如何使用这个GetCurrentSession呢?我们需要在应用程序的配置文件中进行一个配置说明,现在我们打开App.config文件,给session-factory添加一个属性节点,内容如下:
<property name="current_session_context_class">thread_static</property>
如果我们在winform应用程序中,这属性的取值为”thread_static”,如果在web项目中,这个取值为“web”。只有我们设置了这个节点,那么我们才能使用这个方法。我们来更改一下NHibernateHelper这个方法。在提供一个方法用来获得GetCurrentSession得到的ISession对象。
public static ISession GetCurrentSession()
{
return factory.GetCurrentSession();
}
好,我们现在来测试一下这个方法,看看是否能过获得ISession对象。在出程序中,我们更改一下Main方法。
static void Main(string[] args)
{
Console.WriteLine(DAL.NHibernateHelper.GetCurrentSession().IsOpen);
}
运行结果如下:

哦,天啊,怎么会出现异常呢?我们会发现异常信息是”No Session bound to the current context”。没有一个Session和当前上下文绑定。这一点是初学者经常犯的一个错误,我们已经配置了App.config的信息,那么怎么会获得不到呢?大家从上面的信息可以知道,我们只是配置了”要”和当前的线程绑定,但是只是“要”还没有真正的绑定。需要我们来手动的进行一个绑定信息。
根据分析,我们来改写一下NHibernateHelper的方法,能够让我们的GetCurrentSession能够正确运行。
private static void BindSession()
{
if (!CurrentSessionContext.HasBind(factory))
{
CurrentSessionContext.Bind(factory.OpenSession());
}
}
public static ISession GetCurrentSession()
{
BindSession();
return factory.GetCurrentSession();
}
在NHibernateHelper中,我们添加一个方法,就是用来把ISession对象和当前上下文(thread或者是web请求)进行绑定,此时我们在调用GetCurrentSession之前,首先执行一下BindSession来绑定。
然后我们再次运行主程序来测试一下: 
没问题了,但是我们得到的这个ISession对象到底是不是同一个呢?我们再来测试一下,更改主程序代码:
static void Main(string[] args)
{
NHibernate.ISession session1 = DAL.NHibernateHelper.GetCurrentSession();
NHibernate.ISession session2 = DAL.NHibernateHelper.GetCurrentSession();
Console.WriteLine("两个Session是同一个吗?"+(session1 == session2));
}

很显然,两个ISession对象是同一个了!这样我们解决了上面我们提到的那个矛盾问题了。
在本章中,我们讨论了一下如何去管理ISession对象以及如何获得GetCurrentSession来获得同一个ISession对象,达到我们执行事务的目的。希望大家能够从本章中学到一点东西!但是老魏却是很认真的告诉大家,本章很重要哦!
一步步学习NHibernate(6)——ISession的管理的更多相关文章
- 一步步学习NHibernate(1)——NHibernate介绍
请注明转载地址:http://www.cnblogs.com/arhat 第十五章 从本章开始,老魏将给大家一起学习NHibernate这个流行的ORM框架,本来老魏想要和大家一起探讨微软的EF框架的 ...
- 一步步学习NHibernate(7)——HQL查询(1)
请注明转载地址:http://www.cnblogs.com/arhat 从本章开始,老魏带着大家来学习一下HQL语句.HQL语句NHibernate为我们提供的一种功能比较强大的查询语句,这个HQL ...
- 一步步学习NHibernate(5)——多对一,一对多,懒加载(2)
请注明转载地址:http://www.cnblogs.com/arhat 通过上一章的学习,我们建立了Student和Clazz之间的关联属性,并从Student(many)的一方查看了Clazz的信 ...
- 一步步学习NHibernate(4)——多对一,一对多,懒加载(1)
请注明转载地址:http://www.cnblogs.com/arhat 通过上一章的学习,我们学会如何使用NHibernate对数据的简单查询,删除,更新和插入,那么如果说仅仅是这样的话,那么NHi ...
- 一步步学习NHibernate(3)——NHibernate增删改查
请注明转载地址:http://www.cnblogs.com/arhat 在上一章中,我们配置了以下NHibernate的运行环境, 并介绍了NHibernate的中两个非常中重要的接口"I ...
- 一步步学习NHibernate(9)——连接查询和子查询(1)
请注明转载地址:http://www.cnblogs.com/arhat 在前几章中,我们把HQL的基本查询学习了一下,但是只有基本查询很显然不能满足我们的需求,那么就需要一下复杂查询比如" ...
- 一步步学习NHibernate(8)——HQL查询(2)
请注明转载地址:http://www.cnblogs.com/arhat 在上一章中,老魏带着大家学习了HQL语句,发现HQL语句还是非常不错的,尤其是在懒加载的时候,书写起来比较的舒服,但是这里老魏 ...
- 一步步学习NHibernate(2)——配置NHibernate的环境
请注明转载地址:http://www.cnblogs.com/arhat 第二章 环境搭建 在上一章中,我们知道了NHibernate是用来干什么的了,那么今天在本章中,我们开始搭建NHibernat ...
- 一步步学习NHibernate(10)——连接查询和子查询(2)
请注明转载地址:http://www.cnblogs.com/arhat 在上一章中,老魏讲述了HQL的链接查询,本章呢,老魏开始讲述HQL的子查询.子查询在SQL中也是占据着非常重要的作用,如果没有 ...
随机推荐
- Response
Response This improved Response API, able to simplify the Framework's Response management. Practical ...
- Android(java)学习笔记122:TabActivity使用
1.首先我们要知道TabActivity是结合TabHost使用的,于是我们自然而然要说明一下TabHost 所谓的TabHost是提供选项卡(Tab页)的窗口视图容器. 此对象包含两个子对象: 一个 ...
- JFinal极速开发实战-业务功能开发-通用表单验证器
提交表单数据时,需要经过前端的验证才能提交到后台,而后台的验证器再做一道数据的校验,成功之后才能进入action进行业务数据的处理. 在表单数据的验证中,数据类型的验证还是比较固定的.首先是对录入数据 ...
- ubuntu14.04LTS更新源
这两天一直在使用Linux系统做一些事情,但是又会有特别多的报错,其中有一个问题就是源的问题,我知道有太多太多的人写这个源更新的帖子,我现在也写一篇关于源更新的帖子,只是针对ubuntu14.04LT ...
- Javascript中new
// 加不加new结果都一样 var obj = new Function('var temp = 100;this.temp = 200;return temp + this.temp;'); al ...
- NetBeans自定义代码折叠块,类似vs中的#region
//<editor-fold defaultstate="collapsed" desc="测试代码折叠"> echo '<script ty ...
- oracle中decode()函数
简单写写,后续继续补充
- js事件监听机制(事件捕获)总结
在前端开发过程中我们经常会遇到给页面元素添加事件的问题,添加事件的js方法也很多,有直接加到页面结构上的,有使用一些js事件监听的方法,由于各个浏览器对事件冒泡事件监听的机制不同,le浏览器只有事件冒 ...
- C#中的事件-订阅与发布
我们用一个简单的例子,来说明一下这种消息传递的机制. 有一家三口,妈妈负责做饭,爸爸和孩子负责吃...将这三个人,想象成三个类. 妈妈有一个方法,叫做“做饭”.有一个事件,叫做“开饭”.做完饭后,调用 ...
- c#检测端口是否被占用的简单实例
c#检测端口是否被占用的简单实例. 当我们要创建一个Tcp/Ip Server connection ,我们需要一个范围在1000到65535之间的端口 . 但是本机一个端口只能一个程序监听,所以我们 ...