11

我目前正在构建一个 ASP.NET MVC 项目,其中 NHibernate 作为其持久层。

目前,已经实现了一些功能,但只使用本地 NHibernate 会话:访问数据库(读取或写入)的每个方法都需要使用“using()”子句实例化自己的 NHibernate 会话。

问题是我想利用 NHibernate 的延迟加载功能来提高我的项目的性能。

这意味着在呈现视图之前,每个请求都有一个打开的 NHibernate 会话。此外,必须支持同时请求(同时多个会话)。

我怎样才能尽可能干净地做到这一点?

我在网上搜索了一下,了解了 session-per-request 模式。我看到的大多数实现都使用某种 Http*(HttpContext 等)对象来存储会话。此外,使用 Application_BeginRequest/Application_EndRequest 函数很复杂,因为当我只想为每个请求实例化一次会话时,它们会为每个 HTTP 请求(aspx 文件、css 文件、js 文件等)触发。

我担心的是我不希望我的视图或控制器能够访问 NHibernate 会话(或者,更一般地说,NHibernate 命名空间和代码)。这意味着我不想在控制器级别或视图级别处理会话。

我有几个选择。哪一个看起来最好?

  • 使用在控制器操作之前和之后触发的拦截器(如在 GRAILS 中)。这些将打开和关闭会话/交易。这在 ASP.NET MVC 世界中可能吗?
  • 在 Web 上下文中使用 NHibernate 提供的 CurrentSessionContext Singleton。以这个页面为例,我认为这是很有希望的,但这仍然需要控制器级别的过滤器。
  • 使用 HttpContext.Current.Items 存储请求会话。再加上 Global.asax.cs 中的几行代码,可以轻松地为我提供请求级别的会话。但是,这意味着将在 NHibernate 和我的视图(HttpContext)之间注入依赖关系。

非常感谢你!

4

5 回答 5

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 中执行此操作!

于 2010-01-19T06:19:45.747 回答
2

将 DI 与 IoC 一起使用。大多数 IoC 都带有每个请求的实例化行为。

于 2010-01-12T20:22:04.353 回答
2

我的“解决方案”涉及使用 Unity 在控制器中为每个请求注入会话:

http://letsfollowtheyellowbrickroad.blogspot.com/2010/05/nhibernate-sessions-in-aspnet-mvc.html

于 2010-05-16T20:05:03.603 回答
1

看看S#arp 架构。它是 ASP.NET MVC 和 NHibernate 的一个非常好的架构。

于 2010-01-12T01:59:06.433 回答
1

您可以添加一个操作过滤器来管理您的 NHibernate 会话和事务。(这可以在动作或控制器级别完成。)这是一个例子:

http://weblogs.asp.net/srkirkland/archive/2009/09/03/asp-net-mvc-transaction-attribute-using-nhibernate.aspx

于 2010-01-12T02:55:38.063 回答