摘要

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

NHibernate系列文章十七:NHibernate Session管理(附程序下载)的更多相关文章

  1. NHibernate系列文章二十七:NHibernate Mapping之Fluent Mapping基础(附程序下载)

    摘要 从这一节起,介绍NHibernate Mapping的内容.前面文章都是使用的NHibernate XML Mapping.NHibernate XML Mapping是NHibernate最早 ...

  2. NHibernate系列文章二十五:NHibernate查询之Query Over查询(附程序下载)

    摘要 这一篇文章介绍在NHibernate 3.2里引入的Query Over查询,Query Over查询跟Criteria查询类似.首先创建IQueryOver对象,然后通过调用该对象的API函数 ...

  3. NHibernate系列文章二十六:NHibernate查询之SQL Query查询(附程序下载)

    摘要 NHibernate在很早的版本就提供了SQL Query(原生SQL查询),对于很复杂的查询,如果使用其他的查询方式实现比较困难的时候,一般使用SQL Query.使用SQL Query是基于 ...

  4. NHibernate系列文章十九:NHibernate关系之多对多关系(附程序下载)

    摘要 NHibernate的多对多关系映射由many-to-many定义. 从这里下载本文的代码NHibernate Demo 1.修改数据库 添加Product表 添加ProductOrder表 数 ...

  5. 一步步实现windows版ijkplayer系列文章之七——终结篇(附源码)

    一步步实现windows版ijkplayer系列文章之一--Windows10平台编译ffmpeg 4.0.2,生成ffplay 一步步实现windows版ijkplayer系列文章之二--Ijkpl ...

  6. NHibernate系列文章十六:使用程序集管理NHibernate项目(附程序下载)

    摘要 在实际的项目中,经常是将NHibernate的实体关系映射类做成独立的工程(assembly dll),只对外提供Session调用的接口.这个程序集作为数据访问层,可以被上面的多个工程(ASP ...

  7. NHibernate系列文章二十三:NHibernate查询之Criteria查询(附程序下载)

    摘要 上一篇文章介绍了NHibernate HQL,他的缺点是不能够在编译时发现问题.如果数据库表结构有改动引起了实体关系映射的类有改动,要同时修改这些HQL字符串.这篇文章介绍NHibernate面 ...

  8. NHibernate系列文章十八:NHibernate关系之一对多(附程序下载)

    摘要 这篇文章介绍NHibernate最实用的内容:关系映射. NHibernate的关系映射方式有三种: Set:无序对象集合,集合中每一个元素不能重复. List:有序对象集合,集合中的元素可以重 ...

  9. NHibernate系列文章九:NHibernate对象二级缓存上

    摘要 NHibernate的二级缓存由SessionFactory管理,由所有Session共享. NHibernate缓存读取顺序: 首先从一级缓存中读取,如果一级缓存对象存在,则读取一级缓存对象并 ...

随机推荐

  1. linux信号处理时机

    信号号称所谓软中断,事实上,还是没有真正的硬件中断那样能随时改变cpu的执行流 硬件中断之所以能一发生就得到处理是因为处理器在每个指令周期的结尾都会去检查中断,这种粒度是很细的 但是信号的实现只是在进 ...

  2. SPOJ BALNUM

    一开始题看错了...dp[pos][sets][viss],其中sets表示出现次数,viss表示出现没有. #include<iostream> #include<cstdio&g ...

  3. 北京网赛I题 hiho1391 (树状数组、区间覆盖最大值问题)

    题目链接:http://hihocoder.com/problemset/problem/1391 题意:A国和B国向对方分别投射N枚和M枚导弹(发射时间,飞行时间,伤害值),同时两国各自都有防御系统 ...

  4. Debugging Process Startup

    Debugging Process Startup Q:  How do I debug a process's startup code? A: This depends on how the pr ...

  5. ecshop安装常见问题及解决办法

    一,Ecshop首页出现报错:Only variables should be passed by referen 最近想安装一个ECSHOP商城上去,老是报错,出现下面这就话: Strict Sta ...

  6. 关于如何获取/清除 MAXScript 侦听器内的文本

    关于如何获取/清除 MAXScript 侦听器内的文本 用来保存记录?还没想到实际用处,先记上. macroRecorder as string listener as stringclearList ...

  7. 准确理解SO_REUSEADDR

          默认情况下,套接字不同一个正在使用的本地地址绑定到一起.但在少数情况下,仍有必要以这种方式,来实现对一个地址的重复利用.每个连接都是通过它的本地及远程地址的组合,"独一无二&qu ...

  8. graphql 新API 开发方式

    我们知道 GraphQL 使用 Schema 来描述数据,并通过制定和实现 GraphQL 规范 定义了支持 Schema 查询的 DSQL (Domain Specific Query Langua ...

  9. Django教程

    开发环境:Centos7,Django 1.10,Python 2.7 Django入门 本教程内容大部分来源于Django官网,有翻译不到位的欢迎大家指正,这部分的内容有助于新手快速搭建一个网站,让 ...

  10. jquery datatables双击,获取行号。

    function dbClickDatatables(rows) { $("#@(Perfix)tbData tbody tr").dblclick(function(e){ de ...