我目前正在构建一个ASP.NET MVC项目,NHibernate作为其持久层。
目前,已经实现了一些功能,但只使用本地NHibernate会话:访问数据库(读取或写入)的每个方法都需要使用“using()”子句实例化自己的NHibernate会话。
问题在于我想利用NHibernate的延迟加载功能来提高项目的性能。
这意味着每个请求都会打开一个NHibernate会话,直到呈现视图为止。此外,必须支持同时请求(同时多个会话)。
如何尽可能干净地实现这一目标?
我在网上搜索了一下,了解了每个请求的会话模式。我看到的大多数实现使用某种Http *(HttpContext等)对象来存储会话。此外,使用Application_BeginRequest / Application_EndRequest函数很复杂,因为当我只想为每个请求实例化一次会话时,它们会被触发每个HTTP请求(aspx文件,css文件,js文件等)。
我担心的是我不希望我的视图或控制器能够访问NHibernate会话(或者更常见的是NHibernate命名空间和代码)。这意味着我不想在控制器级别处理会话,也不想在视图处理会话。
我有几个选择。哪一个看起来最好?
非常感谢!
答案 0 :(得分:13)
好吧,经过几天的工作,我终于决定使用HttpContext.Current.Items来加载会话。
效果很好!
我是这样做的
import System.Web
class SessionManager {
public static ISession GetSession()
var session = HttpContext.Current.Items["NHibernateSession"];
if (session == null) {
session = ...; // Create session, like SessionFactory.createSession()...
HttpContext.Current.Items.Add("NHibernateSession", session);
}
return session;
}
public static void CloseSession()
{
var session = HttpContext.Current.Items["NHibernateSession"];
if (session != null) {
if (session.IsOpen) {
session.close();
}
HttpContext.Current.Items.Remove("NHibernateSession");
}
}
}
通过使用此类提供的静态方法,可以获得与当前HttpContext(当前Web请求)绑定的会话(例如,在Controller中)。我们需要另一段代码来在请求完成时调用CloseSession()方法。
在Global.asax.cs中:
protected void Application_EndRequest(object sender, EventArgs args)
{
NHibernateSessionManager.CloseSession();
}
会话完成后会自动调用Application_EndRequest事件,因此可以正确关闭会话并将其处理掉。这很有用,因为否则我们必须在每个Controller中执行此操作!
答案 1 :(得分:2)
将DI与IoC一起使用。大多数IoC都带有每请求实例化行为。
答案 2 :(得分:2)
我的“解决方案”涉及使用Unity在控制器中为每个请求注入会话:
http://letsfollowtheyellowbrickroad.blogspot.com/2010/05/nhibernate-sessions-in-aspnet-mvc.html
答案 3 :(得分:1)
看看S#arp Architecture。对于ASP.NET MVC和NHibernate来说,这是一个非常好的架构。
答案 4 :(得分:1)
您可以添加一个可以管理您的NHibernate会话的动作过滤器。交易。 (这可以在动作或控制器级别完成。)以下是一个示例: