注册多个会话工厂很容易 - 问题在于在需要时选择正确的。例如,假设我们有某种具有多个数据库的实验室。每个实验室都有一个位置和该位置的多个样本。我们可以有一个 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。我知道那里有问题。