同じリポジトリに異なるNHibernateセッション(multi-db)を注入する方法

使用方法: ASP.NET MVC3 始まり2 流暢なnHibernate

I have 2 databases (DB1 & DB2). I have one base repository class (Repository) and many Controllers (Controller1, Controller2).

public MyController(IRepository someModelFromDB1Repository, IRepository someModelFromDB2Repository)
{
    [...]
}

public class Repository : IRepository where T : Entity
{
    private readonly ISession _session;

    public Repository(ISessionFactory sessionFactory)
    {
        _session = sessionFactory.OpenSession();
    }
}

public class DB1SessionFactory : ISessionFactory
{
    private readonly NHibernate.ISessionFactory _sessionFactory;

    private ISession _session;

    public DB1SessionFactory()
    {
        [...]
    }
}

public class DB2SessionFactory : ISessionFactory
{
    private readonly NHibernate.ISessionFactory _sessionFactory;

    private ISession _session;

    public DB2SessionFactory()
    {
        [...]
    }
}

今私はMyControllerを作成します。リポジトリを注入したいのですが、そのリポジトリはSessionFactoryを使用してDB1(またはモデルに応じてDB2)を使用する必要があります。

私はそれを正しく注入する方法を理解することができません...私は単一のSessionFactory(DB1)を持っていたとき、ここでNINJECTを持っていました:

kernel.Bind().To()
            .InRequestScope();

kernel.Bind(typeof(IRepository<>)).To(typeof(Repository<>));

編集:

モデルに応じて適切なセッションがリポジトリに注入されることが最善の方法です。一部のモデルはDB2からのDB1および他のモデルからのものであるため、その選択はそれに依存している必要があります。コントローラー/ビューの開発者が(リポジトリーの前に[名前付き]を持つような)何かを気にする必要はないが、それが必要ならば、それは素晴らしいだろう。 [Named]であっても、コントローラの[Named]リポジトリに基づいてリポジトリに適切なセッションを挿入する方法を理解できませんでした...

3
これは、DBを取る基準に大きく依存します。この情報がなければ、この問題に対処する方法がたくさんあるので、あなたに良い答えを与えることはほとんど不可能です。
追加された 著者 Remo Gloor,
それは最終的にモデルに依存します。一部のモデルは1つのDB内にあり、他のモデルは別のDB内にあります。そのロジックがコントローラ/ビューの開発者から隠されている方が良いでしょうが、動作させる方法を見つけることができません。私がSomeModelDB1RepositoryとSomeOtherModelDB2Repositoryを持っているコントローラーコンストラクターでは、適切なセッションが注入されたリポジトリーをそれぞれ持っておきたいです。ありがとう。
追加された 著者 Nick,

1 答え

まず、シェルトン・スコープでセッション・ファクトリを定義し、リクエスト・スコープにセッションを設定する必要があります。

このような設定を行います:

.Bind().To().Named("DB1")
     .InSingletonScope();

.Bind().To().Named("DB2")
     .InSingletonScope();

private bool IsOnDB(IRequest request, string dbName)
{
    var repositoryType = request.ParentRequest.Service;
    var modelType = repositoryType.GetGenericArguments()[0];
    var databaseName = this.GetDatabaseForModel(modelType);

    return databaseName == dbName;
}

.Bind()
    .ToMethod(ctx => ctx.Kernel.Get("DB1").OpenSession())
    .When(r => this.IsOnDb(r, "DB1"))
    .InRequestScope();
.Bind()
    .ToMethod(ctx => ctx.Kernel.Get("DB2").OpenSession())
    .When(r => this.IsOnDb(r, "DB2"))
    .InRequestScope();
2
追加された
セッションを開こうとするときに使用するセッションをどのように指定しますか?
追加された 著者 Todd,
それであなたはあなたの建築について考えるべきです。 Web要求の最後に、すべてのデータベース要求が完了している必要があります。より長い時間にわたってセッションを使用しないでください。ウェブセッション。
追加された 著者 Remo Gloor,
そうではありません。セッションプロバイダがシングルトンで、異なるWebリクエストに対してセッションを再利用するため、結果が間違っています。この場合、あなたは非常に奇妙な行動を取るでしょう。誰がセッションを取得するのか、セッションのプロバイダを取得しないのかを決定します。
追加された 著者 Remo Gloor,
独自のセッションファクトリを必要とせずに、NHibernate Session Factoriesの2つの正しく設定されたインスタンスを使用するだけですらありません。
追加された 著者 Remo Gloor,
あなたが正しいです!プロバイダの代わりに2つのセッションバインディングが必要です。更新された回答をご覧ください。
追加された 著者 Remo Gloor,
ブリリアント!それは素晴らしい作品です。私が得る唯一の問題は、リポジトリがInRequestScopeとして設定したときにほとんどの時間をリポジトリに使用する前にセッションが閉じられるということです。
追加された 著者 Nick,
Webリクエスト内で同じセッションを再利用したい場合(同じDBの異なるリポジトリ間で同じセッション)。セッションは、 "InRequestScope"と宣言されているSessionProviderの内部に格納する必要がありますか?
追加された 著者 Nick,
SessionProviderがすべてのリポジトリに対して一度呼び出されているという誤った仮定がありました。他のリポジトリが同じWebリクエスト内でインスタンス化されたときに、自動的に同じセッションを再利用します。これは素晴らしいことです!残念ながら、異なるセッションファクトリに対してセッションが要求されたときに、セッションプロバイダが再度呼び出されないので、同じコントローラ内の異なるDBを使用して複数のリポジトリを持つという目的を破っています。
追加された 著者 Nick,
完璧!神よ、獣は獣だ、私はそれを熟視することからはほど遠い!この解決策に遭遇する他の人を助けるためのメモだけで、あなたの答えを修正し、ctx.Kernel.Get をctx.Kernel.Get に変更する必要があります!再度、感謝します。
追加された 著者 Nick,