NHibernate:仓储会话管理

4

目前我的代码库有两个构造函数。当我从我的mvc网站调用它们时,总是调用第一个构造函数,从而打开一个新的会话。我应该传递会话吗?我应该如何处理这个问题。

    public CompanyRepository()
    {
        _session = NHibernateHelper.OpenSession();
    }

    public CompanyRepository(ISession session)
    {
        _session = session;
    }




public class NHibernateHelper
    {
        private static ISessionFactory _sessionFactory;

        private static ISessionFactory SessionFactory
        {
            get
            {
                if (_sessionFactory == null)
                {
                    var configuration = new Configuration();
                    configuration.Configure();
                    configuration.AddAssembly(typeof(UserProfile).Assembly);
                    configuration.SetProperty(NHibernate.Cfg.Environment.ConnectionStringName,
                                              System.Environment.MachineName);
                    _sessionFactory = configuration.BuildSessionFactory();
                }
                return _sessionFactory;
            }
        }

        public static ISession OpenSession()
        {
            return SessionFactory.OpenSession();
        }
    }

我正在使用Ninject IOC容器(对我来说非常新)。我有以下容器。我该如何将ISession绑定到CompanyRepository?
 private class EStoreDependencies : NinjectModule
        {
            public override void Load()
            {
                Bind<ICompanyRepository>().To<CompanyRepository>();
                Bind<IUserProfileRepository>().To<UserProfileRepository>();
                Bind<IAddressRepository>().To<AddressRepository>();
                Bind<IRolesService>().To<AspNetRoleProviderWrapper>();
                Bind<IUserService>().To<AspNetMembershipProviderWrapper>();
                Bind<ICurrentUserSerivce>().To<DefaultCurrentUserSerivce>();
                Bind<IPasswordService>().To<AspNetMembershipProviderWrapper>();
                Bind<IStatusResponseRepository>().To<StatusResponseRepository>();
                Bind<ICategoryRepository>().To<CategoryRepository>();
                Bind<IProductRepository>().To<ProductRepository>();
            }
        }
4个回答

3

您应该使用“每个请求一个会话”的模式,通过将ISession对象存储在HttpContext中,在同一HTTP请求期间在存储库和查询之间共享它。

这里是一个使用MVC操作属性的实现示例

还可以通过简单地更改NHibernateHelper类来实现简单/基本的实现,如下所示:

public class NHibernateHelper {
    //...

    const string SessionKey = "NhibernateSessionPerRequest";

    public static ISession OpenSession(){
        var context = HttpContext.Current;

        if(context != null && context.Items.ContainsKey(SessionKey)){
            //Return already open ISession
            return (ISession)context.Items[SessionKey];
        }
        else{
            //Create new ISession and store in HttpContext
            var newSession = SessionFactory.OpenSession();
            if(context != null)
                context.Items[SessionKey] = newSession;

            return newSession;
        }
    }
}

代码尚未编译或测试... 但应该可以正常工作。


1

您的代码或者更好的方式是使用依赖注入,将ISession传递到仓储的构造函数中。这样可以让多个仓储参与到单个事务中。

我支持Paco的建议,让依赖注入框架来处理这个问题。这种方法的挑战在于非Web应用程序没有像HTTP请求-响应周期那样清晰的工作单元边界。我们有一些仓储被Windows Forms和ASP.NET应用程序共享,我们需要在Windows Forms应用程序中手动管理新的仓储实例。


我也是这么想的,我正在使用Ninject(已添加代码)。我该如何将会话绑定到CompanyRepository?对不起,这一切还没有搞清楚。 - frosty
1
Bind<ICompanyRepository>().To<CompanyRepository>().WithConstructorArgument("session", NHibernateHelper.OpenSession());可能有其他的方式来实现。 - Jamie Ide

0

使用控制反转容器


0

尝试使用sessionFactory.GetCurrentSession(),这将允许您访问 上下文会话

这基本上允许您使用“每个请求一个会话”的模型,而无需自己编写代码。您甚至可以选择您的上下文是什么:Http(正如您的示例所示)或其他一些选项(我在我的单元测试中使用CallSessionContext)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接