注册多个会话工厂很容易 - 问题是在需要时选择正确的会话工厂。例如,假设我们有一个拥有多个数据库的实验室。每个实验室都有一个位置和该位置的多个样本。我们可以有一个 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>
因此,我们需要为每个连接字符串拥有一个唯一的会话工厂。让我们创建一个包装 ISessionFactory 的 NamedSessionFactory:
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。首先,您创建的是一个会话工厂 - 这并不是我们正在寻找的。我们想要给我们的工厂一个位置并从中获取一个会话,而不是一个会话工厂。 Fluent 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。我知道那里存在问题。