註冊多個會話工廠很容易 - 問題是在需要時選擇合適的工具。例如,假設我們有某種具有多個數據庫的實驗室。每個實驗室都有一個位置和該位置的多個樣本。我們可以有一個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一點。首先,你創建的是一個會話工廠 - 這不是我們想要的。我們想給我們的工廠一個位置,並從中獲得一個會話,而不是會話工廠。流利的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。我知道那裏有問題。
我也許應該注意到,它已經多年,因爲我用StructureMap或NHibernate的 - 所以我可能會搞砸的東西在那裏。但基本模式應該是健全的。希望能幫助到你! –
一個非常有用的答案。我目前使用StrucutreMap的TheInstanceNamed()來分配SessionFactor到DAO,這似乎工作正常。當我有一點空閒時間時,請考慮實施您的建議。謝謝。 – TonE