应用程序设计:NH会话管理、通用存储库、ASP.NET MVC

本文关键字:存储 ASP NET MVC NH 会话 管理 应用 程序设计 | 更新日期: 2023-09-27 18:21:11

定义了domain model之后,我想弄清楚如何完成其余的工作。


数据访问层

我以前读过,没有必要在ISession上编写自己的UnitOfWork实现(尽管我发现了很多关于如何很好地完成它的信息)。所以我很困惑。。我有这样的存储库界面:

public interface IRepository<T> where T: AbstractEntity<T>, IAggregateRoot
{
    T Get(Guid id);
    IQueryable<T> Get(Expression<Func<T, Boolean>> predicate);
    IQueryable<T> Get();
    T Load(Guid id);
    void Add(T entity);
    void Remove(T entity);
    void Remove(Guid id);
    void Update(T entity);
    void Update(Guid id);
}

在具体实施中有两种选择:

选项A

是通过构造函数注入ISessionFactory,并具有类似于的内容

public class Repository<T> : IRepository<T> where T : AbstractEntity<T>, IAggregateRoot
{
    private ISessionFactory sessionFactory;
    public Repository(ISessionFactory sessionFactory)
    {
        this.sessionFactory = sessionFactory;
    }
    public T Get(Guid id)
    {
        using(var session = sessionFactory.OpenSession())
        {
            return session.Get<T>(id);
        }
    }
}

选项B

是使用NHibernateHelper

using(var session = NHibernateHelper.GetCurrentSession())
{
    return session.Get<T>(id);
}

其中NHibernateHelper

internal sealed class NHibernateHelper
{
    private const string CurrentSessionKey = "nhibernate.current_session";
    private static readonly ISessionFactory sessionFactory;
    static NHibernateHelper()
    {
        sessionFactory = new Configuration().Configure().BuildSessionFactory();
    }
    public static ISession GetCurrentSession()
    {
        HttpContext context = HttpContext.Current;
        ISession currentSession = context.Items[CurrentSessionKey] as ISession;
        if(currentSession == null)
        {
            currentSession = sessionFactory.OpenSession();
            context.Items[CurrentSessionKey] = currentSession;
        }
        return currentSession;
    }
    public static void CloseSession()
    {
        HttpContext context = HttpContext.Current;
        ISession currentSession = context.Items[CurrentSessionKey] as ISession;
        if(currentSession == null)
        {                
            return;
        }
        currentSession.Close();
        context.Items.Remove(CurrentSessionKey);
    }
    public static void CloseSessionFactory()
    {
        if(sessionFactory != null)
        {
            sessionFactory.Close();
        }
    }
} 

首选哪个选项?

为什么(除了注射)?

如果我使用选项A,我将把ISessionFactory的配置放在哪里?

它应该放在ASP.NET MVC项目的某个地方吗?怎样

感谢您阅读这个怪物问题!感谢您的指导!

应用程序设计:NH会话管理、通用存储库、ASP.NET MVC

如何使用mvc处理注入依赖关系在某种程度上是特定于版本的,但总是有助于使用真正的依赖注入(DI)容器。无论您对其进行何种分割,此解决方案都需要将ISession注入存储库,而不是ISessionFactory。这允许DI容器正确地管理会话的生存期。

假设您使用的是Asp.NetMVC3,并且还没有连接到特定DI容器,那么启动Nuget控制台并键入:

install-package Ninject.MVC3

这将下载Ninject(这是一个DI容器)并配置你的mvc应用程序来使用它。它还将创建一个文件~/App_Start/NinjectMVC3.cs,在那里你可以配置你的依赖关系。

private static void RegisterServices(IKernel kernel)
{
    kernel.Bind<ISessionFactory>()
        .ToMethod(c => new Configuration().Configure().BuildSessionFactory())
        .InSingletonScope();
    kernel.Bind<ISession>()
        .ToMethod((ctx) => ctx.Kernel.Get<ISessionFactory>().OpenSession())
        .InRequestScope();
    kernel.Bind<IRepository<>>().To<Repository<>>();        
}   

第一条语句告诉ninject,当某个东西需要ISessionFactory时,它应该延迟初始化NHibernate并创建一个。然后,在应用程序的整个生命周期内,这个会话工厂将作为应用程序范围内的单例进行保存。

第二条语句告诉ninject,当某个东西需要ISession时,它应该获取ISessionFactory的实例并调用OpenSession()。然后,该会话在请求的范围内被重用,并在请求结束时被销毁。

第三条语句告诉ninject,当某个东西需要任何类型的IRepository时,它应该使用内置的逻辑来解决依赖关系。

从这里,您可以按照如下方式编写代码,一切都应该正常工作。

public class WidgetController : Controller
{
    private readonly IRepository<Widget> _repository;
    public WidgetController(IRepository<Widget> repository)
    {
        _repository = repository;
    }
}

关于存储库,我想向您介绍一篇出色的博客文章。存储库是新的Singleton

我通常在我的存储库上使用只读属性,比如这个

    protected  ISession Session
    {
        get
        {
            return NHibernateSessionFactory.CurrentFor(dataBaseFactoryKey);
        }
    }

我的NHibernateSessionFactory是这样工作的。

在web应用程序中,每个web请求都应该使用模式NH会话。我认为每个web请求应该只有一个会话,并且您的存储库应该使用这个会话。要实现这一点,您需要编写IHttpModule,它将在请求开始时打开会话、开始事务并将会话绑定为环境(当前)会话,在请求结束时结束事务并关闭会话。您还需要将current_session_text_class设置为"web"。然后您的Repository/DAO将看起来像这个

    public TEntity Get(object id)
    {
        return sessionFactory.GetCurrentSession().Get<TEntity>(id);
    }

MVC和NHibernate的最佳模式是每个请求的会话
步骤:

  1. 在Global.asax中添加public static ISessionFactorySessionFactory
  2. Application_Start()中配置和构建会话工厂:

    var config=新配置().Configure()
    SessionFactory=配置。BuildSessionFactory();

  3. Application_BeginRequest中打开会话并将其绑定到CurrentSessionContext:

    var nhSession=SessionFactory.OpenSession()
    CurrentSessionContext.Bind(会话);

  4. Application_EndRequest()中解除绑定并处理会话

现在,在您的控制器中,您可以访问您的会话调用:

Global.SessionFactory.GetCurrentSession();

编辑:关注@hival评论

在控制器内部,使用块处理模型,并根据逻辑执行提交/回滚。