1

定义了一个domain model我想弄清楚如何做剩下的工作。


数据访问层

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

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

4 回答 4

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()。然后这个 Session 在请求的范围内被重用,并在请求结束时被销毁。

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

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

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

关于存储库,我想向您指出一篇出色的博文 Repository is the new Singleton

于 2012-01-24T20:59:15.900 回答
1

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

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

我的 NHibernateSessionFactory 像这样工作。

于 2012-01-24T13:37:05.997 回答
1

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

    public TEntity Get(object id)
    {
        return sessionFactory.GetCurrentSession().Get<TEntity>(id);
    }
于 2012-01-24T14:13:53.730 回答
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()中取消绑定并释放会话

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

Global.SessionFactory.GetCurrentSession();

编辑:关注@hival 评论

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

于 2012-01-24T14:43:54.273 回答