0

Я пытаюсь реализовать всевозможные хорошие вещи, такие как UnitOfWork, Repository, DI. Я использую Unity для DI. Вот моя дилемма. У меня есть несколько (в настоящее время 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: У меня есть UnitOfWork, который принимает IDataContextAsync в качестве параметра конструктора. Класс сервисного уровня, в свою очередь, принимает IUnitOfWork как аргумент конструктора. Эти интерфейсы уже зарегистрированы в Unity. Итак, мое предположение - все эти аргументы конструктора автоматически разрешаются Unity, и я не вызываю вручную Resolve для любого из этих параметров конструктора. Надеюсь, это ответит на ваш вопрос. Итак, поскольку мне нужно переопределить или вставить конструктор моего dbContext во время выполнения, является ли единственным вариантом вызвать Resolve где-нибудь в DataContext? –

+0

В конце вашего вопроса вы предоставляете фрагмент кода, который вызывает 'Resolve'. Вы используете этот код где-нибудь? В чем ваш вопрос? –

ответ

0

Я придумал пример, который может быть немного сконструирован, но я считаю, что он дает вам максимальную гибкость. Вы можете увидеть весь пример here. Если вам нужна поддержка времени разработки или поддержка только времени выполнения, возможно, вы немного почистите ее.

Для разрешения времени разработки для этого используется дополнительный параметр generics в качестве токена для идентификации хранилища данных, к которому вы хотите подключиться. Это позволяет вам разрешать (через инсталляцию конструктора) единицу работы и/или репозиторий, специфичный для одного хранилища данных.

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

Для разрешения выполнения, это использует класс менеджера, чтобы получить экземпляр целевого блока работы с строкой маркерами.

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

Менеджеров используют Unity встроенной поддержки для решения всех именованных регистрации в массив. Подробнее об этом можно узнать в этом question and answer.

Обратите внимание, что я предлагаю вам использовать HierarchicalLifetimeManager для регистрации всего, что доступно. Если вы используете это в сочетании с использованием детских контейнеров, у вас будет механизм автоматической утилизации. Больше информации в этом question and answer.

+0

На первый взгляд, ваш образец выглядит как перебор. Но если это произойдет, я предпочел бы использовать избыток решения, чем злоупотреблять шаблоном DI. У меня все еще есть беспокойство. Ваш пример по-прежнему использует контейнер Ioc вне корня композиции. Если бы я хотел это сделать, я мог бы просто создать контейнер. Резолюция с переопределением параметра (я полагаю). Это то, чего я пытаюсь избежать. Затем он становится локатором службы. Вы знаете, что они говорят о локаторах сервисов! Но спасибо за образец. Я сделаю это. –

+0

Он не использует контейнер вне корня композиции. В консольном приложении основным методом является расположение корня композиции и место, которое вам нужно выполнить. Вы можете легко добавить класс сервиса, который имеет те типы, которые я разрешаю в качестве параметров конструктора, без необходимости прямого вызова в контейнер. – TylerOhlsen

+0

Спасибо. Вы были бы добры, чтобы опубликовать образец класса обслуживания, на который вы ссылаетесь? Кроме того, нужно иметь в виду пару вещей. Мой загрузчик для регистрации запускается до входа пользователя в систему. Мне нужно разрешить связанный с пользователем dbcontext со строкой соединения после факта. Кроме вызова container.Resolve with parameteroverride, возможно, в классе входа (к тому времени мы не в составе root), как я могу зарегистрировать правильный dbcontext? –