asp.net-mvc - 使用 NHibernate 和 Autofac 管理多个数据库

标签 asp.net-mvc nhibernate autofac multiple-databases

我想我会在自己思考解决方案时提出这个问题。

在构建了大部分应用程序之后,我有最后一分钟要求支持读取/写入额外的数据库(总共 2 个,不知道其他数据库)。我使用 NHibernate 构建了应用程序,Autofac 提供了 DI/IoC 组件。 FWIW,它驻留在 ASP.NET MVC 2 应用程序中。

我有一个接受 NHibernate session 的通用存储库类。从理论上讲,只要传递给它的 session 是从适当的 SessionFactory 产生的,我就可以继续将这个通用存储库 ( IRepository<> ) 用于第二个数据库,对吗?

好吧,当应用程序启动时,Autofac 就是这样做的。关于 Session 和 SessionFactory,我有一个模块说明:

builder.Register(c => c.Resolve<ISessionFactory>().OpenSession())
    .InstancePerMatchingLifetimeScope(WebLifetime.Request)
    .OnActivated(e =>
    {
        e.Context.Resolve<TransactionManager>().CurrentTransaction = ((ISession)e.Instance).BeginTransaction();
    });

 builder.Register(c => ConfigureNHibernate())
    .SingleInstance();

其中,返回基本 SessionFactory 的 ConfigureNHibernate() 如下所示:
private ISessionFactory ConfigureNHibernate()
{
    Configuration cfg = new Configuration().Configure();
    cfg.AddAssembly(typeof(Entity).Assembly);
    return cfg.Configure().BuildSessionFactory();
}

目前,这仅限于一个数据库。在任何其他 NHib 场景中,我可能会将单独的 SessionFactories 的实例插入散列,并根据需要检索它们。我不想重新设计整个东西,因为我们已经非常接近主要版本了。所以,我猜我至少需要修改上面的方法,以便我可以独立配置两个SessionFactories。我的灰色区域是我将如何指定正确的工厂用于特定的存储库(或至少用于特定于第二个数据库的实体)。

在以这种方式使用 IoC 容器和 NHibernate 时,任何人都有过这种情况的经验吗?

编辑
我已经删除了一个 GetSessionFactory 方法,该方法采用配置文件路径,检查 HttpRuntime.Cache 中是否存在匹配的 SessionFactory,如果不存在则创建一个新实例,并返回该 SessionFactory。现在我仍然需要敲定如何告诉 Autofac 如何以及何时指定适当的配置路径。新方法看起来像(从比利 2006 年的帖子 here 大量借用):
private ISessionFactory GetSessionFactory(string sessionFactoryConfigPath)
    {
        Configuration cfg = null;
        var sessionFactory = (ISessionFactory)HttpRuntime.Cache.Get(sessionFactoryConfigPath);

        if (sessionFactory == null)
        {
            if (!File.Exists(sessionFactoryConfigPath))
                throw new FileNotFoundException("The nhibernate configuration file at '" + sessionFactoryConfigPath + "' could not be found.");

            cfg = new Configuration().Configure(sessionFactoryConfigPath);
            sessionFactory = cfg.BuildSessionFactory();

            if (sessionFactory == null)
            {
                throw new Exception("cfg.BuildSessionFactory() returned null.");
            }

            HttpRuntime.Cache.Add(sessionFactoryConfigPath, sessionFactory, null, DateTime.Now.AddDays(7), TimeSpan.Zero, System.Web.Caching.CacheItemPriority.High, null);
        }

        return sessionFactory;
    }

最佳答案

我假设您希望不同类型的实体进入每个数据库;如果您想在每个数据库中保留相同类型的实体,请查看 AutofacContrib.Multitenant。

可以帮助解决这种情况的两个要素是:

  • 命名服务 http://code.google.com/p/autofac/wiki/TypedNamedAndKeyedServices
  • 解析参数http://code.google.com/p/autofac/wiki/ResolveParameters (关于这个的最少文档 - 即将发布的 Autofac 2.4 版本有一些语法甜味剂...)

  • 首先,使用命名服务来引用两个不同的数据库。我会调用他们"db1""db2 "。与数据库相关的所有组件,一直到 session ,都使用名称注册:
    builder.Register(c => ConfigureDb1())
        .Named<ISessionFactory>("db1")
        .SingleInstance();
    
    builder.Register(c => c.ResolveNamed<ISessionFactory>("db1").OpenSession())
        .Named<ISession>("db1")
        .InstancePerLifetimeScope();
    
    // Same for "db2" and so-on.
    

    现在,假设你有一个类型 NHibernateRepository<T>接受 ISession作为它的构造函数参数,你可以写一个函数WhichDatabase(Type entityType)返回 "db1""db2"当给定实体的类型时。

    我们使用 ResolvedParameter根据实体类型动态选择 session 。
    builder.RegisterGeneric(typeof(NHibernateRepository<>))
        .As(typeof(IRepository<>))
        .WithParameter(new ResolvedParameter(
            (pi, c) => pi.ParameterType == typeof(ISession),
            (pi, c) => c.ResolveNamed<ISession>(
                WhichDatabase(pi.Member.DeclaringType.GetGenericArguments()[0])));
    

    (警告 - 在 Google Chrome 中编译和测试;))

    现在,解决 IRepository<MyEntity>将选择适当的 session , session 将继续被 Autofac 延迟初始化和正确处理。

    当然,您必须仔细考虑事务管理。

    希望这能解决问题!
    注意

    关于asp.net-mvc - 使用 NHibernate 和 Autofac 管理多个数据库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4443937/

    相关文章:

    c# - 为什么我的继承类没有隐藏我的基类方法?

    c# - Autofac 从 Container 解析构造函数实例?

    database - Linq 到具有大数据库的实体

    session - NHibernate、 session 、MVVM 和存储库

    nhibernate - Hibernate/NHibernate 中的枚举表

    c# - 在 IOC 容器中使用委托(delegate)和事件时避免强制依赖关系

    mysql - 如何连接MVC和MYSQL

    .net - 在整个asp.net MVC 4项目中使用基本 Controller

    jquery - ASP.NET MVC Bootstrap 动态模式内容

    c# - 空 linq 查询结果异常