问题
I am trying to implement all sorts of good stuff like UnitOfWork, Repository, DI. I am using Unity for DI. Here is my dilemma. I have a few (currently 3) databases with identical schema but obviously with different data for business reasons (I will call them GroupDB1, GroupDB2 and GroupDB3). I also have a Master Database (DifferentDB) that has a different schema. My dbcontext need to use different databases for different scenarios at runtime. I have no clue how to put them all to work together.
Here is my 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)
{
//......
}
}
and here are my other interfaces and implementations.
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;
}
Since I read a lot about anti-patterns I am reluctant to do
var result = container.Resolve<MyObject>(
new ParameterOverride("x", ExpectedValue)
.OnType<MyOtherObject>());
I am stumped. Any help is highly appreciated. Thanks.
Babu.
回答1:
I came up with an example that might be a bit over engineered, but I believe it gives you the most flexibility. You can see the entire example here. If you only want support for design time or only support for runtime, you can probably clean it up a bit.
For design time resolution, this uses an additional generics parameter as a token to identify the data store you wish to connect to. That allows you to resolve (via constructor injection) a unit of work and/or a repository that is specific to one data store.
MyService(IUnitOfWork<Group2Token> unitOfWork) { /* ... */ }
For runtime resolution, this uses a manager class to retrieve an instance of the desired unit of work with a string token.
MyService(IUnitOfWorkManager unitOfWorkManager)
{
_unitOfWork = unitOfWorkManager.GetUnitOfWork("Group2");
}
The managers use Unity's built-in support for resolving all named registrations into an array. More on that can be found in this question and answer.
Note that I suggest you use HierarchicalLifetimeManager for the registration of anything that's disposable. If you use that in combination with using child containers, you will have an automatic disposal mechanism. More info in this question and answer.
来源:https://stackoverflow.com/questions/38314793/how-would-i-pass-a-constructor-parameter-at-runtime-to-my-dbcontext-and-also-reg