Mit mehreren dbcontext-Instanzen und dependency injection
Dies ist eine ähnliche Frage, die ich hier vor ein paar Wochen mit einer signifikanten änderung in der Anforderung.
Habe ich eine neue und einzigartige (ich habe nicht gefunden, was so in meinem stackoverflow-Suche) fachliche Anforderung:
Habe ich erstellt zwei separate entity framework 6 DbContexts, dass zwei strukturell verschiedenen Datenbanken, nennen wir Sie PcMaster und PcSubs. Während PcMaster ist eine geradlinig-Datenbank und die PcMasterContext wird eine statische Verbindungszeichenfolge, PcSubs-Datenbank dient als Vorlage zum erstellen von neuen Datenbanken aus. Offensichtlich, da die kopierten Datenbanken haben die gleiche Struktur, die Idee ist, ändern Sie einfach die Datenbank (Katalog) Namen in der Verbindungszeichenfolge auf eine andere db als die dbcontext instanziiert wird. Ich habe auch repository-pattern und dependency injection (derzeit Ninject, aber das denken der Umzug in Autofac).
Ich habe nicht gesehen, eine IDbContext Schnittstelle für DbContext, es sei denn, Sie wollen selbst eines erstellen. Aber dann habe ich gesehen, viele sagen, dass es nicht eine gute Idee ist oder nicht die beste Praxis.
Im Grunde, was ich tun möchte, ist, unter bestimmten Bedingungen, nicht nur die Anwendung wechseln muss zwischen PCMasterContext und PCSubsContext, sondern auch ändern Sie die Verbindungszeichenfolge, um PCSubsContext wenn PCSubsContext ist der aktuelle Kontext. die dbContext ich verwendet in das repository muss auf eine andere Datenbank. Ich weiß nicht, wie ich können dies tun, mit einem IoC-container wie Ninject oder Autofac. Hier sind einige code-Schnipsel, die ich bisher erstellt haben. Helfen Sie mit einige wirklich funktionierende Lösungen ist hoch geschätzt.
Hier ist mein interface für die 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);
//...
//...
}
Hier ist meine Zusammenfassung 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
//...
}
Und nun, hier ist die Schnittstelle für eine der abgeleiteten 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!
}
Nun, meine PCSubs dbContext generiert der 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; }
}
Gibt es eine Möglichkeit, ich kann Sie einfach verwenden und/oder injizieren eine generische dbcontext für beide Datenbanken zusammen mit den Verbindungs-string für verschiedene Datenbanken. Wie würde ich die Eintragung der "DbContext" in der Ioc container ohne eine entsprechende Benutzeroberfläche und noch in der Lage zu injizieren, die Verbindungszeichenfolge zur Laufzeit? Einige code-Beispiele, die wirklich helfen.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Die Lösung ist eigentlich ganz einfach. Sie müssen sicherstellen, dass Ihre
PCSubsDBContext
hat einen Konstruktor in einer Verbindungszeichenfolge, connection string name, Datenbank-name, oder etwas ähnliches. Auf diese Weise können Sie die richtigePCSubsDBContext
basierend auf dem Kontext in dem er lebt. Was Wert zu injizieren in Ihren ctor kommt wohl auf den angemeldeten Benutzer oder eine bestimmte Anfrage. Dies ist etwas, was Sie bereits wissen, wie zu tun ist.Registrieren, hängt ein bisschen auf dem container, aber Sie haben in der Regel registrieren Sie einen Delegierten für diese. Dies könnte etwa so Aussehen:
Da das erstellen der Kontext ist abhängig von der Verfügbarkeit einer Anfrage, es könnte sogar gut sein, ändern Sie Ihr design ein wenig, so das
PCSubsDBContext
geladen werden können träge, während Sie immer noch bauen Sie den rest des Objekt-Graphen ohne die Existenz einer web-Anfrage. Dies ist sehr wertvoll, denn so können Sie überprüfen der container-Konfiguration.Die Lösung (wie immer) ist die Einführung einer neuen Abstraktion, wie zum Beispiel:
Nun, statt der Einbringung einer
PCSubsDBContext
direkt in die Verbraucher, Sie können jetzt Spritzen, einIPcSubsContextProvider
und seineContext
- Eigenschaft während der Ausführung (nicht aber während der Aufbau der Objekt-graph). Dies ermöglicht es derPCSubsDBContext
werden nur erstellt, wenn es gebraucht wird, und nur nach dem rest der Objekt-graph erstellt wurde. Eine Umsetzung wäre trivial:Diese Umsetzung kann registriert werden, mit einem Gültigkeitsbereich/request lifestyle:
Danach Einfach Injektor macht es sehr einfach die Konfiguration überprüfen:
Und es erlaubt Ihnen zu tun diagnostizieren Sie Ihre Konfiguration als gut.
Mit den anderen Containern wird dies schwieriger sein, zu tun.