应用程序设计:NH-session管理,通用存储库,ASP.NET MVC

时间:2012-01-24 12:50:53

标签: c# asp.net-mvc nhibernate session fluentvalidation

定义了一个domain model我想知道如何完成剩下的工作。


数据访问权限

我之前已经阅读过没有必要在UnitOfWork上编写自己的ISession实现代码(thogh我发现了很多关于如何做得很好的信息)。所以我很困惑..我有这样的存储库界面:

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项目的某个地方吗?怎么样?

感谢您阅读怪物问题!非常感谢您的指导!

4 个答案:

答案 0 :(得分:2)

如何使用mvc处理注入依赖项在某种程度上是特定于版本的,但始终有助于使用真正的依赖注入(DI)容器。无论您如何切片,此解决方案都需要您将ISession注入存储库而不是ISessionFactory。这允许您的DI容器正确管理会话的生命周期。

假设您使用的是Asp.Net MVC 3并且没有附加到特定的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;
    }
}

关于存储库我想指出一篇优秀的博文Repository is the new Singleton

答案 1 :(得分:1)

我通常在我的存储库中使用只读属性,就像这样

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

我的NHibernateSessionFactory就像this一样。

答案 2 :(得分:1)

在网络应用中,您应该根据网络请求使用模式NH会话。我认为每个Web请求应该只有一个会话,并且您的存储库应该使用此单个会话。 要实现这一点,您需要编写IHttpModule,它将打开会话,开始事务并在请求开始时将会话绑定为环境(当前)会话,并在请求结束时结束事务和关闭会话。您还需要将current_session_context_class设置为“web”。然后您的Repository / DAO将如下所示

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

答案 3 :(得分:0)

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

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

    var config = new Configuration()。Configure();
    SessionFactory = config.BuildSessionFactory();

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

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

  4. Application_EndRequest()取消绑定并处置会话

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

    Global.SessionFactory.GetCurrentSession();
    

    编辑:关注@hival评论

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