0

UnitOfWork, Repository, DI와 같은 모든 종류의 좋은 것들을 구현하려고합니다. DI 용 Unity를 사용하고 있습니다. 여기 내 딜레마가있다. 필자는 동일한 스키마를 가진 몇 가지 (현재 3 개) 데이터베이스를 가지고 있지만 분명히 비즈니스상의 이유로 서로 다른 데이터를 가지고 있습니다 (나는 GroupDB1, GroupDB2 및 GroupDB3라고 부름). 다른 스키마가있는 마스터 데이터베이스 (DifferentDB)도 있습니다. dbcontext는 런타임시 다른 시나리오에 대해 다른 데이터베이스를 사용해야합니다. 나는 그들 모두가 함께 일할 수있는 방법이 없다.런타임시 생성자 매개 변수를 dbContext에 전달하고 유니티와 같이 등록하는 방법은 무엇입니까?

은 여기 내 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

여기서 '해결'방법은 무엇입니까? –

+0

@Yacoub : IDataContextAsync를 생성자 매개 변수로 사용하는 UnitOfWork가 있습니다. 서비스 레이어 클래스는 차례대로 IUnitOfWork를 생성자 인수로 사용합니다. 이 인터페이스들은 이미 Unity에 등록되어 있습니다. 그래서, 제 생각에 이러한 모든 생성자 인수는 Unity에 의해 자동으로 해결되며 이러한 생성자 매개 변수 중 하나에서 Resolve를 수동으로 호출하지 않습니다. 희망이 당신의 질문에 대한 답변. 그래서, 런타임에 내 dbContext의 생성자를 오버라이드하거나 삽입해야하기 때문에 DataContext의 Resolve를 호출하는 유일한 방법은 무엇입니까? –

+0

질문 끝에 '해결'을 호출하는 코드 스 니펫을 제공합니다. 이 코드를 어딘가에서 사용하고 있습니까? 당신의 질문은 정확히 무엇입니까? –

답변

0

저는 약간의 설계가 될 수있는 예를 생각해 냈습니다. 그러나 저는 이것이 당신에게 최고의 유연성을 줄 것이라고 믿습니다. 전체 예제 here을 볼 수 있습니다. 디자인 타임에 대한 지원 만 원하거나 런타임에 대한 지원 만 원할 경우 조금 청소할 수 있습니다.

디자인 시간 해상도의 경우 추가 제네릭 매개 변수를 토큰으로 사용하여 연결할 데이터 저장소를 식별합니다. 이를 통해 하나의 데이터 저장소에 특정한 작업 단위 및/또는 저장소를 생성자 주입을 통해 확인할 수 있습니다.

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

런타임 해석의 경우, 매니저 클래스를 사용하여 문자열 토큰으로 원하는 작업 단위 (UOW)의 인스턴스를 검색합니다.

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

매니저는 사용 유니티에 내장 된 배열로 모든 이름 등록을 해결하기위한 지원을 제공합니다. 그것에 대한 자세한 내용은 question and answer에서 확인할 수 있습니다.

일회용으로 등록 할 때는 HierarchicalLifetimeManager을 사용하는 것이 좋습니다. 하위 컨테이너를 조합하여 사용하는 경우 자동 처리 메커니즘이 제공됩니다. 이 question and answer에 대한 자세한 정보.

+0

표면이 과잉 인 것처럼 보입니다. 그러나 그것이 내려 오면 차라리 DI 패턴을 남용하는 것보다는 과도한 해결책을 사용하게 될 것입니다. 나는 여전히 관심이있다. 귀하의 예제는 여전히 컴포지션 루트 외부의 IOC 컨테이너를 사용합니다. 그 일을하고 싶다면 컨테이너를 만들 수 있습니다. 매개 변수 오버라이드로 해결할 수 있습니다 (아마도). 이것이 내가 피하려고하는 것입니다. 그런 다음 서비스 위치 지정자가됩니다. 그들이 서비스 탐지기에 대해 말하는 것을 알고 있습니다! 하지만 샘플을 가져 주셔서 감사합니다. 나는 한 발을 내줄 것이다. –

+0

컴포지션 루트 외부의 컨테이너는 사용하지 않습니다. 콘솔 앱에서 주요 방법은 합성 루트의 위치와 해결해야 할 장소입니다. 컨테이너에 직접 호출 할 필요없이 생성자 매개 변수로 해결하는 유형의 서비스 클래스를 쉽게 추가 할 수 있습니다. – TylerOhlsen

+0

감사합니다. 추천하고있는 서비스 클래스의 샘플을 게시 할만큼 친절하십니까? 또한 염두에 두어야 할 몇 가지. 사용자가 로그인하기 전에 등록을위한 부트 스트 래퍼가 실행됩니다. 사실 후에 연결 문자열로 사용자 관련 dbcontext를 해결해야합니다. 아마도 login 클래스에서 parameteroverride를 사용하여 container.Resolve를 호출하는 것 이외에는 (그때까지는 구성 루트에 있지 않습니다.) 올바른 dbcontext를 등록하려면 어떻게해야합니까? –