《NHibernate One Session Per Request 简单实现》勘误
2010-02-02 22:08
405 查看
使用 NHibernate 进行 Web 开发的朋友大多都知道 Session-Per-Request 模式,但网上真正能够正确使用的例子不多,网上包括园子里好多文章犯了同一个错误,而这个错误确一直在散播...
首先对 NHibernate 进行配置没有错:
<property name='current_session_context_class'>web</property>
错误在类 NHinbernateSessionFactory(类名都写错了) 中,NHinbernateSessionFactory.GetCurrentSession 不应包含对 HttpContext 的操作,GetCurrentSession 其实本应很简单,请参见(类名改成 NHibernateHelper,简短):
public sealed class NHibernateHelper
{
public static readonly ISessionFactory SessionFactory;
static NHibernateHelper()
{
SessionFactory = new Configuration()
.Configure()
.AddAssembly(/**/)
.BuildSessionFactory();
}
public static ISession GetCurrentSession()
{
return SessionFactory.GetCurrentSession();
}
}
将 current_session_context_class 配置为 web,NHibernate 在初始化时会生成 NHibernate.Context.WebSessionContext 类的实例,WebSessionContext 类源码如下:
[Serializable]
public class WebSessionContext : MapBasedSessionContext
{
// Fields
private const string SessionFactoryMapKey = "NHibernate.Context.WebSessionContext.SessionFactoryMapKey";
// Methods
public WebSessionContext(ISessionFactoryImplementor factory) : base(factory)
{ }
protected override IDictionary GetMap()
{
return (HttpContext.Current.Items[SessionFactoryMapKey] as IDictionary);
}
protected override void SetMap(IDictionary value)
{
HttpContext.Current.Items[SessionFactoryMapKey] = value;
}
}
WebSessionContext 实现了 Session-Per-Request 模式,它封装了 HttpContext ,因此我们不需要在我们的辅助类(NHibernateSessionFactory 或是 NHibernateHelper)中再对 HttpContext 进行操作。
public interface ICurrentSessionContext
{
ISession CurrentSession();
}
可以从下图中看出:
NHibernate.Context 命名空间中的类和接口
(说明:current_session_context_class 还可以配置为 Managed_web、Call、thread_static,分别对应类 ManagedWebSessionContext、CallSessionContext、ThreadStaticSessionContext)
在实际使用中我们并不需要直接调用 WebSessionContext 的 CurrentSession() 方法,因为 ISessionFactory 提供了一个更简单的方法让我们能一步获取到 Session:
public interface ISessionFactory : IDisposable
{
ISession GetCurrentSession();
//......
}
下面探讨一下 ISessionFactory.GetCurrentSession 方法的具体实现:
1 public sealed class SessionFactoryImpl
2 : ISessionFactoryImplementor, IMapping, ISessionFactory, IDisposable, IObjectReference
3 {
4 private readonly ICurrentSessionContext currentSessionContext;
5
6 public ISession GetCurrentSession()
7 {
8 if (this.currentSessionContext == null)
9 {
10 throw new HibernateException(
11 "No CurrentSessionContext configured (set the property current_session_context_class)!");
12 }
13 return this.currentSessionContext.CurrentSession();
14 }
15
16 public ICurrentSessionContext CurrentSessionContext
17 {
18 get { return this.currentSessionContext; }
19 }
20
21 private ICurrentSessionContext BuildCurrentSessionContext()
22 {
23 string name = PropertiesHelper.GetString("current_session_context_class", this.properties, null);
24 string str2 = name;
25 if (str2 != null)
26 {
27 if (str2 == "call") return new CallSessionContext(this);
28 if (str2 == "thread_static") return new ThreadStaticSessionContext(this);
29 if (str2 == "web") return new WebSessionContext(this);
30 if (str2 == "managed_web") return new ManagedWebSessionContext(this);
31 }
32 else
33 return null;
34 try
35 {
36 Type type = ReflectHelper.ClassForName(name);
37 return (ICurrentSessionContext)Environment.BytecodeProvider.ObjectsFactory
38 .CreateInstance(type, new object[] { this });
39 }
40 catch (Exception exception)
41 {
42 log.Error("Unable to construct current session context [" + name + "]", exception);
43 return null;
44 }
45 }
46 //......
47 }
SessionFactoryImpl 在实例化时会调用 BuildCurrentSessionContext() 方法(行21)为 currentSessionContext 字段赋值,具体值有配置文件中的 current_session_context_class 决定。
ISessionFactory 的 GetCurrentSession() 调用的是 ICurrentSessionContext 的 CurrentSession()(行6) 方法。
上面的代码相当简单,想必大家都已经明明白白了。
1. 并不是每一次请求都需要一个 Session 来访问数据库。文中 Global.asax 的代码给所有的请求在开始的时候都进行WebSessionContext.Bind(),会照成很多 Session 的浪费,虽然 NHibernate 的 Session 是轻量级的,较为合理的做法是在“真正需要”时绑定。
2. 因为 WebSessionContext.Unbind 方法需要一个 ISessionFactory 接口的实例,迫使用我们的辅助类(NHibernateSessionFactory 或是 NHibernateHelper)公开 SessionFactory。
第一个问题比较容易解决,留在回复中和大家交流吧。
第二个问题我会在下一篇随笔中解答。
本人学习 NHibernate 时间也不长,属于新手,如有错误,欢迎指正!
源码下载(仅供参考)
《NHibernate One Session Per Request 简单实现》
先来看园子里 Flyear 的一篇文章 《NHibernate One Session Per Request 简单实现》。首先对 NHibernate 进行配置没有错:
<property name='current_session_context_class'>web</property>
错误在类 NHinbernateSessionFactory(类名都写错了) 中,NHinbernateSessionFactory.GetCurrentSession 不应包含对 HttpContext 的操作,GetCurrentSession 其实本应很简单,请参见(类名改成 NHibernateHelper,简短):
public sealed class NHibernateHelper
{
public static readonly ISessionFactory SessionFactory;
static NHibernateHelper()
{
SessionFactory = new Configuration()
.Configure()
.AddAssembly(/**/)
.BuildSessionFactory();
}
public static ISession GetCurrentSession()
{
return SessionFactory.GetCurrentSession();
}
}
将 current_session_context_class 配置为 web,NHibernate 在初始化时会生成 NHibernate.Context.WebSessionContext 类的实例,WebSessionContext 类源码如下:
[Serializable]
public class WebSessionContext : MapBasedSessionContext
{
// Fields
private const string SessionFactoryMapKey = "NHibernate.Context.WebSessionContext.SessionFactoryMapKey";
// Methods
public WebSessionContext(ISessionFactoryImplementor factory) : base(factory)
{ }
protected override IDictionary GetMap()
{
return (HttpContext.Current.Items[SessionFactoryMapKey] as IDictionary);
}
protected override void SetMap(IDictionary value)
{
HttpContext.Current.Items[SessionFactoryMapKey] = value;
}
}
WebSessionContext 实现了 Session-Per-Request 模式,它封装了 HttpContext ,因此我们不需要在我们的辅助类(NHibernateSessionFactory 或是 NHibernateHelper)中再对 HttpContext 进行操作。
思路
我们只需要从 WebSessionContext 的实例中获取 Session 即可。从WebSessionContext 类中获取当前 ISession 相当简单,因为 WebSessionContext 实现了 ICurrentSessionContext 接口:public interface ICurrentSessionContext
{
ISession CurrentSession();
}
可以从下图中看出:
NHibernate.Context 命名空间中的类和接口
(说明:current_session_context_class 还可以配置为 Managed_web、Call、thread_static,分别对应类 ManagedWebSessionContext、CallSessionContext、ThreadStaticSessionContext)
在实际使用中我们并不需要直接调用 WebSessionContext 的 CurrentSession() 方法,因为 ISessionFactory 提供了一个更简单的方法让我们能一步获取到 Session:
public interface ISessionFactory : IDisposable
{
ISession GetCurrentSession();
//......
}
下面探讨一下 ISessionFactory.GetCurrentSession 方法的具体实现:
具体实现
Configuration.BuildSessionFactory 方法实际返回的是 SessionFactoryImpl 类的实例,让我们简单看一下 SessionFactoryImpl 的部分代码吧:1 public sealed class SessionFactoryImpl
2 : ISessionFactoryImplementor, IMapping, ISessionFactory, IDisposable, IObjectReference
3 {
4 private readonly ICurrentSessionContext currentSessionContext;
5
6 public ISession GetCurrentSession()
7 {
8 if (this.currentSessionContext == null)
9 {
10 throw new HibernateException(
11 "No CurrentSessionContext configured (set the property current_session_context_class)!");
12 }
13 return this.currentSessionContext.CurrentSession();
14 }
15
16 public ICurrentSessionContext CurrentSessionContext
17 {
18 get { return this.currentSessionContext; }
19 }
20
21 private ICurrentSessionContext BuildCurrentSessionContext()
22 {
23 string name = PropertiesHelper.GetString("current_session_context_class", this.properties, null);
24 string str2 = name;
25 if (str2 != null)
26 {
27 if (str2 == "call") return new CallSessionContext(this);
28 if (str2 == "thread_static") return new ThreadStaticSessionContext(this);
29 if (str2 == "web") return new WebSessionContext(this);
30 if (str2 == "managed_web") return new ManagedWebSessionContext(this);
31 }
32 else
33 return null;
34 try
35 {
36 Type type = ReflectHelper.ClassForName(name);
37 return (ICurrentSessionContext)Environment.BytecodeProvider.ObjectsFactory
38 .CreateInstance(type, new object[] { this });
39 }
40 catch (Exception exception)
41 {
42 log.Error("Unable to construct current session context [" + name + "]", exception);
43 return null;
44 }
45 }
46 //......
47 }
SessionFactoryImpl 在实例化时会调用 BuildCurrentSessionContext() 方法(行21)为 currentSessionContext 字段赋值,具体值有配置文件中的 current_session_context_class 决定。
ISessionFactory 的 GetCurrentSession() 调用的是 ICurrentSessionContext 的 CurrentSession()(行6) 方法。
上面的代码相当简单,想必大家都已经明明白白了。
补充
《NHibernate One Session Per Request 简单实现》 一文中还有两处不太恰当的地方:1. 并不是每一次请求都需要一个 Session 来访问数据库。文中 Global.asax 的代码给所有的请求在开始的时候都进行WebSessionContext.Bind(),会照成很多 Session 的浪费,虽然 NHibernate 的 Session 是轻量级的,较为合理的做法是在“真正需要”时绑定。
2. 因为 WebSessionContext.Unbind 方法需要一个 ISessionFactory 接口的实例,迫使用我们的辅助类(NHibernateSessionFactory 或是 NHibernateHelper)公开 SessionFactory。
第一个问题比较容易解决,留在回复中和大家交流吧。
第二个问题我会在下一篇随笔中解答。
本人学习 NHibernate 时间也不长,属于新手,如有错误,欢迎指正!
源码下载(仅供参考)
相关文章推荐
- NHibernate One Session Per Request简单实现
- Nhibernate one Session per Request的实现
- NHibernate Session Management(One per request)
- request和session以及application辨析(并用application实现简单的网页计数器)
- Entity Framework在Asp.net MVC中的实现One Context Per Request(附源码)
- Entity Framework在Asp.net MVC中的实现One Context Per Request(附源码)
- javaWeb的session和cookie实现记住密码自动登录功能简单实例
- Session简单实现购物功能
- 【IOS】利用ASIHTTPRequest 实现一个简单的登陆验证
- Struts2工具类[实现获取Request/Response/Session与绕过jsp/freemaker直接输出文本的简化函数]
- 【IOS】利用ASIHTTPRequest 实现一个简单的登陆验证
- PHP 用session与gd库实现简单验证码生成与验证的类方法
- 用Nhibernate怎么实现数据的添加、删除、修改简单程序
- Python-Django简单实现session登录注销
- 分布式集群Session共享 简单多tomcat8+redis的session共享实现
- 【IOS】利用ASIHTTPRequest 实现一个简单的登陆验证
- 在Core环境下用WebRequest连接上远程的web Api 实现数据的简单CRUD(续)
- 应用Druid进行数据源、SQL、Web应用、URI、Session等监控的简单实现
- 用Nhibernate怎么实现数据的添加、删除、修改简单程序
- session 注册简单验证码的实现