#database #asp.net-mvc-3 #fluent-nhibernate #structuremap #multi-tenant
#База данных #asp.net-mvc-3 #свободно-nhibernate #structuremap #многопользовательский
Вопрос:
В настоящее время я использую 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 встроенный способ справиться с этим?
Ответ №1:
У меня это сработало в модуле a
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. Спасибо, я попробую. Являются ли все
.RegionPrefix("IMB")
(предположительно, идентификатор клиента) родными для NHibernate?2. Нет .RegionPrefix — это префикс кэша, который fn использует для обработки кэшированных объектов
3. при ближайшем рассмотрении это не влияет на строку подключения, основанную на каких-либо идентификаторах клиентов. Насколько это многопользовательское решение?
4. Извините, я неправильно понял ваш вопрос. Вы можете попробовать это. ссылка , откуда вы вызываете свой загрузчик? глобальный.asax?
Ответ №2:
Проблема в том, что вы действительно хотите, чтобы ваш 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
, но, возможно, создание схем баз данных в веб-приложениях в любом случае не такая уж отличная идея?