每个租户的数据库,使用Fluent NHibernate& StructureMap

时间:2011-04-19 15:09:13

标签: database asp.net-mvc-3 fluent-nhibernate structuremap multi-tenant

我目前正在使用StructureMap将NHibernateRegistry实例注入我的DAL,它将NHibernate配置为单个连接字符串,并为我的单用户应用程序启动Singleton FluentConfiguration

如何根据路由URL中的{tenant}路由参数修改Fluent NHibernate配置以使用其他数据库?

路由示例:

{tenant}/{controller}/{action}/{id}

... branch1/Home/Indexbranch2/Home/Index的请求使用相同的应用程序代码,但使用不同的数据库来检索显示的数据。

我过去通过注入每个请求TenantContext对象来解决StructureMap和LINQ的这个问题,该对象从HttpContext检索路由参数,它被接受为构造函数参数并指定了不同的LINQ数据背景。

然而,我怀疑NHibernate处理这个问题比我做饭更好。

部分NHibernateRegistry

public class NHibernateRegistry : Registry
{
    // ... private vars here

    public NHibernateRegistry()
    {
        var cfg = Fluently.Configure()
            .Database(MsSqlConfiguration
                .MsSql2008.ConnectionString(c => 
                    c.FromConnectionStringWithKey("TenantConnectionStringKey")))
                    // where to inject this key?
            .ExposeConfiguration(BuildSchema)
            .Mappings(x => 
                x.FluentMappings.AddFromAssembly(typeof(UserMap).Assembly)

        For<FluentConfiguration>().Singleton().Use(cfg);

        var sessionFactory = cfg.BuildSessionFactory();

        For<ISessionFactory>().Singleton()
            .Use(sessionFactory);
        For<ISession>().HybridHttpOrThreadLocalScoped()
            .Use(x => x.GetInstance<ISessionFactory>().OpenSession());
        For<IUnitOfWork>().HybridHttpOrThreadLocalScoped()
            .Use<UnitOfWork>();
        For<IDatabaseBuilder>().Use<DatabaseBuilder>();

    }
}

StructureMap配置:

public static class Bootstrapper
{
    public static void ConfigureStructureMap()
    {
        ObjectFactory.Initialize(Init);
    }

    private static void Init(IInitializationExpression x)
    {
        x.AddRegistry(new NHibernateRegistry()); // from Data project
    }
}

我是NHibernate的新手,所以我不确定我的会话和配置范围。 NHibernate有内置的方法来处理这个吗?

2 个答案:

答案 0 :(得分:0)

这对我来说是一个模块

return Fluently.Configure()
            .Database(MsSqlConfiguration.MsSql2008.ConnectionString(x => x.FromConnectionStringWithKey("IMB"))
            .Cache(c => c.UseQueryCache().QueryCacheFactory<StandardQueryCacheFactory>()
                         .RegionPrefix("IMB")
                         .ProviderClass<HashtableCacheProvider>()
                         .UseMinimalPuts()).UseReflectionOptimizer())
            .Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.Load("IMB.Data")))
           .Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.Load("IMB.Security")))

           .ExposeConfiguration(
            c => c.SetProperty("current_session_context_class", "web"))
            .ExposeConfiguration(cfg => _configuration = cfg)
            .BuildSessionFactory();

答案 1 :(得分:0)

问题是你真的希望你的ISessionFactory对象是单身人士。这意味着在创建ISessionFactory时指定连接字符串的最佳 not 。您是否尝试过创建ISessionFactory而未指定连接字符串,然后将手动创建的连接传递给ISessionFactory.OpenSession

例如:

public ISession CreateSession()
{
    string tennantId = GetTennantId();
    string connStr = ConnectionStringFromTennant(tennantId);
    SqlConnection conn = new SqlConnection(connStr);
    conn.Open();
    session = sessionFactory.OpenSession(conn);
}

然后告诉StructureMap调用此方法。

缺点是你现在无法在创建ISessionFactory时构建数据库模式,但是在Web应用程序中创建数据库模式也不是一个好主意吗?