每个租户的数据库使用 Fluent NHibernate &结构图

发布于 2024-11-02 04:28:59 字数 2131 浏览 1 评论 0原文

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

我应该如何修改 Fluent NHibernate 配置以根据路由 URL 中的 {tenant} 路由参数使用不同的数据库?

路由示例:

{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 有内置的方法来处理这个问题吗?

I'm currently using StructureMap to inject an NHibernateRegistry instance into my DAL, which configures NHibernate for a single connection string and bootstraps a Singleton FluentConfiguration for my single-user app.

How should I modify my Fluent NHibernate configuration to use a different database based on a {tenant} routing parameter in my routing URL?

Routing example:

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

...where requests for branch1/Home/Index and branch2/Home/Index use the same application code, but different databases to retrieve the data displayed.

I solved this problem in the past for StructureMap and LINQ by injecting a per-request TenantContext object, which retrieved the routing parameter from the HttpContext it accepted as a constructor parameter and specified a different LINQ data context.

However, I suspect NHibernate has a better of handling this than I could cook up.

Partial NHibernateRegistry class

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 configuration:

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

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

I'm new to NHibernate, so I am unsure of scoping my sessions and configurations. Does NHibernate have a built-in way to handle this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

偏闹i 2024-11-09 04:28:59

这在模块中对我有用

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();

This worked for me in an a module

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();
离线来电— 2024-11-09 04:28:59

问题是您确实希望您的 ISessionFactory 对象成为单例。这意味着在创建 ISessionFactory 时最好不要指定连接字符串。您是否尝试过在不指定连接字符串的情况下创建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 应用程序中创建数据库架构不是一个好主意吗?

The problem is that you really want your ISessionFactory object to be a singleton. This means its best not to specify the connection string when creating the ISessionFactory. Have your tried creating the ISessionFactory without specifying a connection string and then passing a manually created connection to ISessionFactory.OpenSession?

For example:

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

And then tell StructureMap to call this method.

The downside is that you can't now from build the database schema when creating the ISessionFactory, but maybe creating database schemas in web applications isn't that great an idea anyway?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文