Mit mehreren DbContexts mit einem generischen repository und unit of work
Meine Bewerbung wird immer größer und so weit ich habe ein Einzelzimmer MyDbContext
muss, die alle Tabellen die ich brauche in meiner Anwendung. Ich möchte (aus Gründen der übersicht) Sie Aufteilung in mehrere DbContext
wie MainDbContext
, EstateModuleDbContext
, AnotherModuleDbContext
und UserDbContext
.
Ich bin nicht sicher, wie dies geschieht vermutlich, wie ich jetzt bin mit dependecy injection (ninject), um meinen DbContext auf meine UnitOfWork-Klasse wie:
kernel.Bind(typeof(IUnitOfWork)).To(typeof(UnitOfWork<MyDbContext>));
Sollte ich ablegen dieser Ansatz mit dependency injection und explizite setzen der DbContext
ich möchte auf meine Leistungen wie:
private readonly EstateService _estateService;
public HomeController()
{
IUnitOfWork uow = new UnitOfWork<MyDbContext>();
_estateService = new EstateService(uow);
}
Statt:
private readonly EstateService _estateService;
public HomeController(IUnitOfWork uow)
{
_estateService = new EstateService(uow);
}
Oder gibt es einen anderen besseren Ansatz? Auch als Zwischenfrage, ich dont wie an der uow
zu meinem service - gibt es einen anderen (besseren) Ansatz?
Code
Ich habe diese IDbContext und MyDbContext:
public interface IDbContext
{
DbSet<T> Set<T>() where T : class;
DbEntityEntry<T> Entry<T>(T entity) where T : class;
int SaveChanges();
void Dispose();
}
public class MyDbContext : DbContext, IDbContext
{
public DbSet<Table1> Table1 { get; set; }
public DbSet<Table2> Table1 { get; set; }
public DbSet<Table3> Table1 { get; set; }
public DbSet<Table4> Table1 { get; set; }
public DbSet<Table5> Table1 { get; set; }
/* and so on */
static MyDbContext()
{
Database.SetInitializer<MyDbContext>(new CreateDatabaseIfNotExists<MyDbContext>());
}
public MyDbContext()
: base("MyDbContext")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
}
}
Dann habe ich das IRepository und die Umsetzung:
public interface IRepository<T> where T : class
{
IQueryable<T> GetAll();
void Add(T entity);
void Delete(T entity);
void DeleteAll(IEnumerable<T> entity);
void Update(T entity);
bool Any();
}
public class Repository<T> : IRepository<T> where T : class
{
private readonly IDbContext _context;
private readonly IDbSet<T> _dbset;
public Repository(IDbContext context)
{
_context = context;
_dbset = context.Set<T>();
}
public virtual IQueryable<T> GetAll()
{
return _dbset;
}
public virtual void Add(T entity)
{
_dbset.Add(entity);
}
public virtual void Delete(T entity)
{
var entry = _context.Entry(entity);
entry.State = EntityState.Deleted;
_dbset.Remove(entity);
}
public virtual void DeleteAll(IEnumerable<T> entity)
{
foreach (var ent in entity)
{
var entry = _context.Entry(ent);
entry.State = EntityState.Deleted;
_dbset.Remove(ent);
}
}
public virtual void Update(T entity)
{
var entry = _context.Entry(entity);
_dbset.Attach(entity);
entry.State = EntityState.Modified;
}
public virtual bool Any()
{
return _dbset.Any();
}
}
Und die IUnitOfWork und umgesetzt, die Griffe der Arbeit mit dem DbContext
public interface IUnitOfWork : IDisposable
{
IRepository<TEntity> GetRepository<TEntity>() where TEntity : class;
void Save();
}
public class UnitOfWork<TContext> : IUnitOfWork where TContext : IDbContext, new()
{
private readonly IDbContext _ctx;
private readonly Dictionary<Type, object> _repositories;
private bool _disposed;
public UnitOfWork()
{
_ctx = new TContext();
_repositories = new Dictionary<Type, object>();
_disposed = false;
}
public IRepository<TEntity> GetRepository<TEntity>() where TEntity : class
{
//Checks if the Dictionary Key contains the Model class
if (_repositories.Keys.Contains(typeof(TEntity)))
{
//Return the repository for that Model class
return _repositories[typeof(TEntity)] as IRepository<TEntity>;
}
//If the repository for that Model class doesn't exist, create it
var repository = new Repository<TEntity>(_ctx);
//Add it to the dictionary
_repositories.Add(typeof(TEntity), repository);
return repository;
}
public void Save()
{
_ctx.SaveChanges();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (this._disposed) return;
if (disposing)
{
_ctx.Dispose();
}
this._disposed = true;
}
}
Was ist der Grund für die Spaltung der Kontext überhaupt? Auch wenn Sie sich aufteilen , können Sie nicht verwenden, DI. Ich wußte auch nicht, wie Sie Ihre Einheit von Arbeit mit Respository heruntergeladen werden(Wörterbuch-Sache)
Ich werde mehrere Module in meiner Anwendung, und eben nicht zu verschmutzen MyDbContext mit einer Menge von Modulen, die DbSets. Vielleicht sollte ich einfach ignorieren?
Hallo Dan, können Sie vorschlagen, eine bessere Ansatz. Ich bin offen für Vorschläge
Ich wollte dies streng, weil 'IdentityDbContext' (MVC5 & OWIN) mit den Transaktionen, die meine 'AppDbContext'. Der UserManager ist zu finden und gut, aber ich hätte gerne ein wenig mehr Kontrolle, wenn man lose gekoppelte relationale Daten zwischen den beiden.
InformationsquelleAutor janhartmann | 2013-12-12
Du musst angemeldet sein, um einen Kommentar abzugeben.
Nicht teilen Sie Ihre modulare Daten-Stücke in mehreren
DbContext
s, es sei denn, es sind logische Nähte für so tun. Personen ausDbContextA
keine automatische navigation oder eine Sammlung von Eigenschaften, die mit Personen inDbContextB
. Wenn Sie split-Rahmen, der code müsste dafür verantwortlich sein, manuell erzwingen Integritätsregeln und laden von Verwandte Daten zwischen verschiedenen Kontexten.Für "Gründen der übersicht" (a.k.ein. halten Sie Ihre geistige Gesundheit), können Sie immer noch organisieren Ihre CLR-code-und Datenbank-Tabellen-Modul. Für die POCO ist, halten Sie Sie in verschiedenen Ordnern unter verschiedenen namespaces. Für Tabellen, können Sie die Gruppe von Schemas. (Allerdings sollte man wohl auch Sicherheitsaspekte zu berücksichtigen, wenn die Organisation von SQL-schema. Zum Beispiel, wenn dort sind alle db-Benutzer sollten eingeschränkten Zugriff auf bestimmte Tabellen, entwerfen des schemas nach diesen Regeln zu.) Dann können Sie dies bei der Erstellung des Modells:
Nur zusammen mit einem separaten
DbContext
wenn deren Entitäten haben keine Beziehungen mit den Entitäten in Ihrem erstenDbContext
.Ich Stimme auch mit Wiktor, daß ich das nicht mag-Schnittstelle & Umsetzung design. Ich nicht besonders wie
public interface IRepository<T>
. Auch, warum deklarieren mehrerepublic DbSet<TableN> TableN { get; set; }
in IhremMyDbContext
? Tun Sie mir einen gefallen, Lesen Sie dieser Artikel, dann Lesen Sie diese eine.Können Sie erheblich vereinfachen den code mit einem EF-interface-design wie diesem:
Wenn Sie erklären
MyDbContext : ICommandEntities
Sie nur ein paar Methoden implementieren die Schnittstelle (meist Einzeiler). Sie können dann Spritzen Sie eine der 3 Schnittstellen in Ihrem service-Implementierungen: in der RegelICommandEntities
bei Operationen, die Nebeneffekte haben, undIQueryEntities
für Operationen, die nicht. Alle services (oder service von Dekorateure), nur verantwortlich für das speichern des Zustands kann eine AbhängigkeitIUnitOfWork
. Ich bin nicht einverstanden, dassController
s sollte eine AbhängigkeitIUnitOfWork
obwohl. Mit der vor design, Ihre Dienste sollten änderungen speichern, bevor Sie die Rückkehr zu denController
.Wenn mehrere separate
DbContext
Klassen in Ihrem app überhaupt Sinn macht, können Sie tun, als Wiktor schlägt und machen die oben genannten Schnittstellen generische. Sie können dann in Abhängigkeit injizieren Sie in Dienstleistungen, etwa so:Erstellen von breiten pro-Aggregat (oder noch schlimmer pro Person) repository-Schnittstellen zu kämpfen, mit EF, multiplizieren langweilig Sanitär-code, und über-inject Ihre Konstruktoren. Stattdessen, geben Sie Ihre Dienste mehr Flexibilität. Methoden wie
.Any()
gehören nicht auf die Schnittstelle, können Sie einfach anrufen Erweiterungen auf derIQueryable<T>
zurückgegebenQuery<T>
oderFindMany<T>
innerhalb Ihrer service-Methoden."beste Methode" ist vertretbar. Ich habe noch um zu sehen, eine Schnittstelle Modell, das besser ist als die oben genannten meiner Meinung nach nur, basierend auf die Arten von Projekten ich arbeite auf (mittlere bis große). Implementieren Sie tatsächlich alle 3 von den Schnittstellen auf
DbContext
, aber daICommandEntities
implementiert, die beiden anderen 2, Sie müssen nur geben Sie es in der Klasse Signatur.Wäre es zu viel zu Fragen, wie diese ICommandEntities in der Praxis verwendet wird? Ich denke, ich kann nicht meinen Verstand auf nicht mit eine repository-Klasse
InformationsquelleAutor danludwig
Ihre Arbeitseinheit, die Schnittstelle ist nicht generisch, aber die Umsetzung ist. Der einfachste Weg, um aufzuräumen wäre, zu entscheiden, und Folgen der gleichen Konvention.
Zum Beispiel, machen Sie Ihre generische Schnittstelle auch. Auf diese Weise konnte Sie registrieren, mit drei verschiedenen Schnittstellen (die gleiche Schnittstelle mit drei verschiedenen generischen Parameter), um drei unterschiedliche Implementierungen:
Und ja, das ist eine gute Idee, Spritzen Sie Ihre Einheit von arbeiten in Controller /Dienstleistungen.
InformationsquelleAutor Wiktor Zychla