Регистрация нескольких фабрик сессий проста - проблема в выборе правильного, когда вам это нужно. Например, допустим, у нас есть какая-то лаборатория с несколькими базами данных. Каждая лаборатория имеет местоположение и несколько образцов для этого места. Мы могли бы иметь SampleRepository, который моделирует это. Каждое местоположение имеет уникальный ключ для его идентификации (например, «LabX», «LabY», «BlackMesa»). Мы можем использовать этот уникальный ключ в качестве имени строки подключения к базе данных в файле app.config. В этом примере у нас будет три строки подключения в файле app.config. Вот пример раздела connectionStrings:
<connectionStrings>
<add name="LabX" connectionString="Data Source=labx;User ID=someuser;Password=somepassword"/>
<add name="LabY" connectionString="Data Source=laby;User ID=someuser;Password=somepassword"/>
<add name="BlackMesa" connectionString="Data Source=blackmesa;User ID=freemang;Password=crowbar"/>
</connectionStrings>
Таким образом, нам нужна уникальная фабрика сеансов для каждой строки подключения. Давайте создадим NamedSessionFactory, который обертывает ISessionFactory:
public interface INamedSessionFactory
{
public string Name { get; } // The name from the config file (e.g. "BlackMesa")
public ISessionFactory SessionFactory { get; }
}
public class NamedSessionFactory : INamedSessionFactory
{
public string Name { get; private set; }
public ISessionFactory SessionFactory { get; private set; }
public NamedSessionFactory(string name, ISessionFactory sessionFactory)
{
Name = name;
SessionFactory = sessionFactory;
}
}
Теперь нам нужно немного изменить ваш AppSessionFactory. Во-первых, вы создали фабрику сессий - это не совсем то, что мы ищем. Мы хотим дать нашей фабрике местоположение и получить сессию, а не сессионную фабрику. Свободный NHibernate - это то, что дает нам сессионные фабрики.
public interface IAppSessionFactory
{
ISession GetSessionForLocation(string locationKey);
}
Хитрость заключается в том, чтобы принять список объектов INamedSessionFactory в конструкторе. StructureMap должен предоставить нам все объекты INamedSessionFactory, которые мы зарегистрировали. Мы доберемся до регистрации через секунду.
public class AppSessionFactory : IAppSessionFactory
{
private readonly IList<INamedSessionFactory> _factories;
public AppSessionFactory(IEnumerable<INamedSessionFactory factories)
{
_factories = new List<INamedSessionFactory>(factories);
}
Здесь происходит волшебство. Учитывая ключ местоположения, мы просматриваем наш список фабрик, ища одно с тем же именем, что и locationKey, затем просим его открыть сеанс и вернуть его вызывающей стороне.
public ISession GetSessionForLocation(string locationKey)
{
var sessionFactory = _factories.Where(x => x.Name == locationKey).Single();
return sessionFactory.OpenSession();
}
}
Теперь давайте соединим все это вместе.
internal class NHibernateRegistry : Registry
{
public NHibernateRegistry()
{
Мы собираемся перебрать все строки подключения в нашем файле app.config (их будет три в этом примере) и зарегистрировать объект INamedSessionFactory для каждой из них.
foreach (ConnectionStringSettings location in ConfigurationManager.ConnectionStrings)
{
For<INamedSessionFactory>()
.Singleton()
.Use(x => new NamedSessionFactory(
location.Name,
GetSessionFactory(location.ConnectionString));
}
Нам также необходимо зарегистрировать IAppSessionFactory.
For<IAppSessionFactory>()
.Singleton()
.Use<AppSessionFactory>();
}
Вы заметите, что мы удалили эту логику из фабричного класса ... Это вспомогательные методы для создания фабрик сессий из Fluent NHibernate.
private static ISessionFactory GetSessionFactory(string connectionString)
{
return GetConfig(connectionString)
.BuildSessionFactory();
}
public static FluentConfiguration GetConfig(string connectionString)
{
return Fluently.Configure()
.Database(MsSqlConfiguration.MsSql2005.ConnectionString(x => x.Is(connectionString)))
.Mappings(
x => x.FluentMappings.AddFromAssemblyOf<AppEntity>());
}
}
Это должно сделать это! Давайте создадим репозиторий для получения наших образцов ...
public class SampleRepository
{
private readonly IAppSessionFactory _factory;
public SampleRepository(IAppSessionFactory factory)
{
_factory = factory;
}
public IEnumerable<Sample> GetSamplesForLocation(Location location)
{
using (ISession session = _factory.GetSessionForLocation(location.Key)
{
foreach (Sample sample in session.Query<Sample>())
yield return sample;
}
}
}
Теперь вы можете получить один экземпляр SampleRepository и использовать метод GetSamplesForLocation для извлечения образцов из любой из трех баз данных, которые мы зарегистрировали в app.config. Хотелось бы избежать BlackMesa. Я понимаю, что там были проблемы.