请注明转载地址: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的管理的更多相关文章

  1. 一步步学习NHibernate(1)——NHibernate介绍

    请注明转载地址:http://www.cnblogs.com/arhat 第十五章 从本章开始,老魏将给大家一起学习NHibernate这个流行的ORM框架,本来老魏想要和大家一起探讨微软的EF框架的 ...

  2. 一步步学习NHibernate(7)——HQL查询(1)

    请注明转载地址:http://www.cnblogs.com/arhat 从本章开始,老魏带着大家来学习一下HQL语句.HQL语句NHibernate为我们提供的一种功能比较强大的查询语句,这个HQL ...

  3. 一步步学习NHibernate(5)——多对一,一对多,懒加载(2)

    请注明转载地址:http://www.cnblogs.com/arhat 通过上一章的学习,我们建立了Student和Clazz之间的关联属性,并从Student(many)的一方查看了Clazz的信 ...

  4. 一步步学习NHibernate(4)——多对一,一对多,懒加载(1)

    请注明转载地址:http://www.cnblogs.com/arhat 通过上一章的学习,我们学会如何使用NHibernate对数据的简单查询,删除,更新和插入,那么如果说仅仅是这样的话,那么NHi ...

  5. 一步步学习NHibernate(3)——NHibernate增删改查

    请注明转载地址:http://www.cnblogs.com/arhat 在上一章中,我们配置了以下NHibernate的运行环境, 并介绍了NHibernate的中两个非常中重要的接口"I ...

  6. 一步步学习NHibernate(9)——连接查询和子查询(1)

    请注明转载地址:http://www.cnblogs.com/arhat 在前几章中,我们把HQL的基本查询学习了一下,但是只有基本查询很显然不能满足我们的需求,那么就需要一下复杂查询比如" ...

  7. 一步步学习NHibernate(8)——HQL查询(2)

    请注明转载地址:http://www.cnblogs.com/arhat 在上一章中,老魏带着大家学习了HQL语句,发现HQL语句还是非常不错的,尤其是在懒加载的时候,书写起来比较的舒服,但是这里老魏 ...

  8. 一步步学习NHibernate(2)——配置NHibernate的环境

    请注明转载地址:http://www.cnblogs.com/arhat 第二章 环境搭建 在上一章中,我们知道了NHibernate是用来干什么的了,那么今天在本章中,我们开始搭建NHibernat ...

  9. 一步步学习NHibernate(10)——连接查询和子查询(2)

    请注明转载地址:http://www.cnblogs.com/arhat 在上一章中,老魏讲述了HQL的链接查询,本章呢,老魏开始讲述HQL的子查询.子查询在SQL中也是占据着非常重要的作用,如果没有 ...

随机推荐

  1. JS获取活动区域高和宽

    var width;            var height;            //获取窗口宽度            if (window.innerWidth)              ...

  2. c语言面试题之sizeof

    c语言面试题之sizeof */--> c语言面试题之sizeof Table of Contents 1. sizeof 1 sizeof sizeof是c语言中判断数据类型或者表达式的长度符 ...

  3. Java内存模型——可见性

    /** * 可见性问题 * @author Snway * */public class Visibility {        private static boolean stop;        ...

  4. Linux编程简介

    Linux编程可以分为Shell(如BASH.TCSH.GAWK.Perl.Tcl和Tk等)编程和高级语言(C语言,C++语言,java语言等)编程,Linux程序需要首先转化为低级机器语言即所谓的二 ...

  5. HTTP层 —— CSRF保护

    简介 跨站请求伪造是一种通过伪装授权用户的请求来利用授信网站的恶意漏洞.Laravel 使得防止应用遭到跨站请求伪造攻击变得简单. Laravel 自动为每一个被应用管理的有效用户会话生成一个 CSR ...

  6. nginx 错误日志分析 以及说明

    1.日志简介 nginx日志主要有两种:访问日志和错误日志.访问日志主要记录客户端访问nginx的每一个请求,格式可以自定义:错误日志主要记录客户端访问nginx出错时的日志,格式不支持自定义.两种日 ...

  7. SQL SERVER 主键约束

    主键约束: 遵循关系型模型中的第二范式.唯一的识别一条记录,不能为空. CREATE TABLE Persons ( Id_P int NOT NULL PRIMARY KEY, LastName v ...

  8. HW—字符串最后一个单词的长度,单词以空格隔开。

    描述 计算字符串最后一个单词的长度,单词以空格隔开. 知识点 字符串,循环 运行时间限制 0M 内存限制 0 输入 一行字符串,长度小于128. 输出 整数N,最后一个单词的长度. 样例输入 hell ...

  9. Ext.Net学习笔记16:Ext.Net GridPanel 折叠/展开行

    Ext.Net学习笔记16:Ext.Net GridPanel 折叠/展开行 Ext.Net GridPanel的行支持折叠/展开功能,这个功能个人觉得还说很有用处的,尤其是数据中包含图片等内容的时候 ...

  10. Ubuntu将程序图标加到启动器

    问题: Ubuntu中安装一些程序的时候图标可能没有放到启动器中,不方便使用. 解决问题: 因为FileZilla这个程序是直接解压缩之后便可以使用的,每次都需要到文件所在目录Filezilla/bi ...