0

UnitOfWork、Repository、DIなど、あらゆる種類の良いものを実装しようとしています。 DIのためにUnityを使用しています。ここに私のジレンマがあります。私は同じスキーマを持ついくつか(現在3つ)のデータベースを持っていますが、明らかにビジネス上の理由から異なるデータを持っています(私はそれらをGroupDB1、GroupDB2、およびGroupDB3と呼んでいます)。私はまた別のスキーマを持つマスターデータベース(DifferentDB)を持っています。私のdbcontextは、実行時にさまざまなシナリオで異なるデータベースを使用する必要があります。私はそれらをすべて一緒に働かせる方法を知りません。実行時にdbContextにコンストラクタパラメータを渡し、Unityにそのようなものを登録するにはどうすればいいですか?

は、ここに私のdbContexts

public partial class GroupDB2 : DataContext 
{ 
    public GroupDB2() : base("name=GroupDB2") 
    { 
    } 
    public IDbSet<T> Set<T>() where T : EntityBase { return base.Set<T>(); } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     //...... 
    } 
} 

public partial class MasterDB : DataContext 
{ 
    public MasterDB() : base("name=MasterDB") 
    { 
    } 
    public IDbSet<T> Set<T>() where T : EntityBase { return base.Set<T>(); } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     //...... 
    } 
} 

、ここで私の他のインタフェースと実装されています。私はアンチパターンについて多くを読んでいるので

public class DataContext : DbContext, IDataContextAsync 
{ 
    private readonly Guid _instanceId; 
    bool _disposed; 

    public DataContext(string nameOrConnectionString) : base(nameOrConnectionString) 
    { 
     _instanceId = Guid.NewGuid(); 
     //Configuration.LazyLoadingEnabled = false; 
     //Configuration.ProxyCreationEnabled = false; 
    } 
} 

public interface IDataContext : IDisposable 
{ 
    int SaveChanges(); 
} 


public interface IDataContextAsync : IDataContext 
{ 
    Task<int> SaveChangesAsync(CancellationToken cancellationToken); 
    Task<int> SaveChangesAsync(); 
} 

public interface IRepository<T> where T : class 
{ 
    IDataContextAsync Context { get; } 
    IDbSet<T> DbSet { get; } 
    void Add(T entity); 
    void Delete(T entity); 
    void Delete(dynamic id); 
    T FindOne(Expression<Func<T, bool>> predicate); 
    IQueryable<T> FindBy(Expression<Func<T, bool>> predicate); 
    IQueryable<T> GetAll(); 
    void Update(T entity); 
} 

public interface IRepositoryAsync<TEntity> : IRepository<TEntity> where TEntity : class 
{ 
    Task<TEntity> FindAsync(params object[] keyValues); 
    Task<TEntity> FindAsync(CancellationToken cancellationToken, params object[] keyValues); 
    Task<bool> DeleteAsync(params object[] keyValues); 
    Task<bool> DeleteAsync(CancellationToken cancellationToken, params object[] keyValues); 
} 

public static IUnityContainer InitializeContainer(IUnityContainer _container) 
{ 
    container = _container; 

    .... 
    .... 

    container.RegisterType<IDataContextAsync, DataContext>(new InjectionConstructor("name=MasterDB")); 
    container.RegisterType<IUnitOfWorkAsync, UnitOfWork>();// ("Async"); 

    // Here is where I have no clue how do I register and resolve the correct entity context based on some conditions 
    // Like ConnectionStringService.GetConnectionString(for some condition); 

    //container.RegisterType<IDataContextAsync, DataContext>("GroupDB", new InjectionConstructor(xxxxxx)); 
    //container.RegisterType<IDataContextAsync, DataContext>("DifferentDB", new InjectionConstructor(yyyyyy)); 

    .... 
    .... 

    return container; 
} 

私は困惑しています

var result = container.Resolve<MyObject>(
    new ParameterOverride("x", ExpectedValue) 
     .OnType<MyOtherObject>()); 

行うには消極的です。どんな助けも高く評価されます。ありがとう。

babu。

+0

ここで、 'Resolve'メソッドを呼び出していますか? –

+0

@Yacoub:IDataContextAsyncをコンストラクタパラメータとして受け取るUnitOfWorkがあります。サービスレイヤークラスは、IUnitOfWorkをコンストラクターの引数として受け取ります。これらのインターフェイスはUnityに既に登録されています。したがって、これらのコンストラクタ引数はすべてUnityによって自動的に解決されると私は想定しており、これらのコンストラクタパラメータのいずれかでResolveを手動で呼び出すことはありません。これはあなたの質問に答えることを願っています。ですから、私は実行時にdbContextのコンストラクタをオーバーライドしたり注入したりする必要があるので、DataContextのどこかでResolveを呼び出す唯一のオプションはありますか? –

+0

あなたの質問の終わりに、あなたは 'Resolve'を呼び出すコードスニペットを提供します。このコードをどこかで使っていますか?あなたの質問は何ですか? –

答えて

0

私は少し工夫されているかもしれない例を考え出しましたが、私はそれがあなたに最も柔軟性を与えると信じています。例here全体を見ることができます。デザインタイムのみのサポートやランタイムのみのサポートが必要な場合は、おそらくそれを少しきれいにすることができます。

設計時の分解能では、追加のジェネリックパラメータをトークンとして使用して、接続先のデータストアを識別します。これにより、1つのデータストアに固有の作業単位および/またはリポジトリを(コンストラクタインジェクションを介して)解決することができます。ランタイム解決のため

MyService(IUnitOfWork<Group2Token> unitOfWork) { /* ... */ } 

、これは、文字列トークンでワークの所望の単位のインスタンスを取得するために管理クラスを使用します。

MyService(IUnitOfWorkManager unitOfWorkManager) 
{ 
    _unitOfWork = unitOfWorkManager.GetUnitOfWork("Group2"); 
} 

管理者は、アレイにすべてのという名前登録を解決するためのユニティのビルトインサポートを使用しています。その詳細はquestion and answerにあります。

使い捨てのものの登録にはHierarchicalLifetimeManagerを使用することをお勧めします。子コンテナを組み合わせて使用​​する場合は、自動廃棄メカニズムを使用します。このquestion and answerの詳細情報

+0

表面には、サンプルが過度のように見えます。しかし、それが下に来れば、私はむしろDIパターンを悪用することよりもむしろ解決策の過度な使用を望むでしょう。私はまだ心配している。あなたの例では、コンポジション・ルートの外側でIOCコンテナが使用されています。もし私がそれをしたければ、私はちょうどコンテナを行うことができます。パラメータのオーバーライドで解決します(私はそうです)。これは私が避けようとしていることです。その後、サービスロケータになります。彼らはサービスロケータについて何を言っているのか知っています!しかし、サンプルのおかげで。私はそれを撃つだろう。 –

+0

コンポジションルート以外のコンテナは使用しません。コンソールアプリケーションでは、主な方法は、コンポジションルートの場所と解決する必要がある場所です。コンテナに直接呼び出す必要がなく、コンストラクタパラメータとして解決するタイプのサービスクラスを簡単に追加できます。 – TylerOhlsen

+0

ありがとうございます。あなたはあなたが参考にしているサービスクラスのサンプルを投稿するのに十分親切でしょうか?また、心に留めておくべきことがいくつかあります。私のブートストラッパーは、ユーザーがログインする前に実行されます。私は、事実の後に接続文字列でユーザーに関連するdbcontextを解決する必要があります。おそらくログインクラスでparameteroverrideを使用してcontainer.Resolveを呼び出す以外(これまでにコンポジションルートにはありません)、正しいdbcontextを登録するにはどうすればよいですか? –

関連する問題