База данных на каждого арендатора с помощью Fluent NHibernate & StructureMap - PullRequest
2 голосов
/ 19 апреля 2011

В настоящее время я использую StructureMap для внедрения экземпляра NHibernateRegistry в мой DAL, который настраивает NHibernate для одной строки подключения и загружает Singleton FluentConfiguration для моего однопользовательского приложения.

Как мне изменить конфигурацию Fluent NHibernate для использования другой базы данных на основе параметра маршрутизации {tenant} в URL-адресе маршрутизации?

Пример маршрутизации:

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

... где запросы для branch1/Home/Index и branch2/Home/Index используют один и тот же код приложения, но разные базы данных для извлечения отображаемых данных.

Я решил эту проблему в прошлом для StructureMap и LINQ, внедрив объект TenantContext для каждого запроса, который извлек параметр маршрутизации из 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 голосов
/ 01 мая 2011

Проблема в том, что вы действительно хотите, чтобы ваш 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, но, возможно, создание схем базы данных в веб-приложениях не так уж и хорошая идея?

0 голосов
/ 29 апреля 2011

Это сработало для меня в модуле

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