7

Fluent NHibernateを使用しているAsp.Net MVC 3アプリケーションで作業しています。私は、StructureMapを使用してIoCコンテナを追加しようとしています。Structure Map、NHibernate、複数のデータベース

私はコントローラを作成し、依存関係を注入するためにStructureMapを使用するカスタムコントローラファクトリを実装しました。各コントローラコンストラクタは1つ以上のサービスを受け取り、DAOをコンストラクタ引数として受け取ります。各DAOコンストラクタはISessionFactoryをとります。私は、次のしている私のStructureMap NHibernateのレジストリのために

internal class NHibernateRegistry : Registry 
{ 
    public NHibernateRegistry() 
    { 
     var connectionString = ConfigurationManager.ConnectionStrings["AppDb"].ConnectionString; 

     For<ISessionFactory>() 
       .Singleton() 
       .Use(x => new AppSessionFactory().GetSessionFactory(connectionString)); 

     For<ISession>() 
      .HybridHttpOrThreadLocalScoped() 
      .Use(x => x.GetInstance<ISessionFactory>().OpenSession()); 
    } 

} 

public class AppSessionFactory 
{ 
    public 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>()); 
    } 
} 

これはすべて、単一のデータベースと、単一のセッションファクトリの正常に動作します。ただし、アプリケーションは複数のデータベースを使用します。

これを処理する最善の方法は何ですか?

答えて

9

複数のセッションファクトリを登録するのは簡単です。問題は必要なときに適切なものを選択することです。たとえば、複数のデータベースを持つ何らかの研究室があるとします。各ラボには、そのロケーションのロケーションと複数のサンプルがあります。私たちはそれをモデル化するSampleRepositoryを持つことができます。各場所には、その場所を識別する固有のキー(「LabX」、「LabY」、「BlackMesa」など)があります。このユニークキーは、app.configファイルのデータベース接続文字列の名前として使用できます。この例では、app.configファイルに3つの接続文字列があります。

したがって、接続文字列ごとに固有のセッションファクトリが必要です。さんは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オブジェクトを提供する必要があります。私たちは1秒で登録を取得します。

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() 
    { 

我々は(この例では、これらの3が存在することになる)私たちの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の単一のインスタンスを取得し、我々はapp.configをで登録した3つのデータベースのいずれかからのサンプルを引っ張ってGetSamplesForLocationメソッドを使用することができます...私たちのサンプルで取得するためのリポジトリを作成してみましょう。しかしBlackMesaを避けたいかもしれません。そこに問題があると私は理解しています。

+0

する必要があります私はおそらく、私はのStructureMapまたはNHibernateはを使用していたので、それが年をされていることに注意しなければならない - ので、私はそこに何かをねじ込まれている場合があります。しかし、基本的なパターンは健全でなければなりません。それが役に立てば幸い! –

+0

本当に便利な答えです。私は現在、StrucutreMapのTheInstanceNamed()を使用してSessionFactoriesをDAOに割り当てていますが、これは問題なく動作しています。私は少し余裕があるときにあなたの提案を実装することになります。ありがとう。 – TonE

0

このことは確実に機能しますか? 文字列ISessionFactory

public string ISessionFactory SessionFactory { get; private set; } 

これは

public interface INamedSessionFactory 
{ 
    ISessionFactory SessionFactory { get; set; } 
    string Name { get; } 
} 

public class NamedSessionFactory : INamedSessionFactory 
{ 
    public ISessionFactory SessionFactory { get; set; } 
    public string Name { get; private set; } 

    public NamedSessionFactory(string Name, ISessionFactory SessionFactory) 
    { 
     this.Name = Name; 
     this.SessionFactory = SessionFactory; 
    } 
} 
関連する問題