This is kind of a similar question I asked here a few weeks ago with one significant change in requirement.
I have a new and unique (I have not found anything like this in my stackoverflow search) business requirement:
I have created two separate entity framework 6 DbContexts that point to two structurally different databases, let us call them PcMaster and PcSubs. While PcMaster is a straight forward database and the PcMasterContext will have a static connection string, PcSubs database is used as a template to create new databases out of. Obviously, since these copied databases will have the same exact structure, the idea is to just change the database (catalog) name in the connection string to point to a different db when the dbcontext is instantiated. I have also used repository pattern and dependency injection (currently Ninject, but thinking of moving to Autofac).
I have not seen an IDbContext interface for DbContext, unless you want to create one yourself. But then, I have seen many saying that it is not a good idea or not the best practice.
Basically, what I want to do is, under certain conditions, not only the application needs to switch between PCMasterContext and PCSubsContext, but also modify the connection string to PCSubsContext if PCSubsContext is the current context. the dbContext I used in the repository needs to point to a different database. I don't know how I can do this with an IoC container such as Ninject or Autofac. Here are some code snippets I have created so far. Help with some real working solutions is highly appreciated.
Here is my interface for the base repository
public interface IPCRepositoryBase<T> where T : class
{
void Add(T entity);
void Delete(T entity);
T FindOne(Expression<Func<T, bool>> predicate);
IQueryable<T> FindBy(Expression<Func<T, bool>> predicate);
IQueryable<T> GetAll();
void SetConnection(string connString);
//...
//...
}
Here is my abstract repository base
public abstract class PCRepositoryBase<T> : IPCRepositoryBase<T>, IDisposable where T : class
{
protected readonly IDbSet<T> dbSet;
protected DbContext dbCtx;
public PCRepositoryBase(DbContext dbCtx)
{
this.dbCtx = dbCtx;
dbSet = dbCtx.Set<T>();
}
public void SetConnection(string connString)
{
dbCtx.Database.Connection.ConnectionString = connString;
}
public IQueryable<T> FindBy(Expression<Func<T, bool>> predicate)
{
return dbSet.Where(predicate); // DataContext.Set<T>().Where( predicate );
}
public virtual IQueryable<T> GetAll()
{
return dbSet;
}
public T FindOne(Expression<Func<T, bool>> predicate)
{
return dbSet.SingleOrDefault(predicate);
}
//... Not all implementations listed
//...
}
And now, here is the interface for one of the derived repositories:
public interface ISubscriberRepository : IPCRepositoryBase<Subscriber>
{
IQueryable<Subscriber> GetByStatusName( PCEnums.enumSubsStatusTypes status );
IQueryable<Subscriber> GetByBusinessName( string businessName );
//...
//...
}
public class SubscriberRepository : PCRepositoryBase<Subscriber>, ISubscriberRepository
{
public SubscriberRepository( DbContext context ) : base( context ) { }
public IQueryable<Subscriber> GetByStatusName( PCEnums.enumSubsStatusTypes status )
{
return FindBy(x => x.SubsStatusType.Name == status.ToString());
}
public IQueryable<Subscriber> GetByBusinessName( string businessName )
{
return FindBy( s => s.BusinessName.ToUpper() == businessName.ToUpper() );
}
//... other operations omitted for brevity!
}
Now, my PCSubs dbContext generated by the designer:
public partial class PCSubsDBContext : DbContext
{
public PCSubsDBContext() : base("name=PCSubsDBContext")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
public virtual DbSet<Currency> Currencies { get; set; }
public virtual DbSet<DurationName> DurationNames { get; set; }
public virtual DbSet<Subscriber> Subscribers { get; set; }
}
Is there a way, I can just use and/or inject one generic dbcontext for both databases along with the connection string for different databases. How would I register the "DbContext" in the Ioc container without a corresponding interface and still be able to inject the connection string at runtime? Some code examples will really help.