2014-09-28 5 views
5

Ich plane, eine Webanwendung mit ASP.NET MVC mit Entity Framework 6 (Code First/POCO) zu entwickeln. Ich möchte auch generisches Repository und Unit of Work Pattern in meiner Anwendung verwenden. Diese Anwendung verbindet sich mit mehr als zwei Datenbanken, also muss ich mehrere DbContext in der Anwendung verwenden.Best Practice von Repository und Einheit der Arbeit Muster mit mehreren DbContext

public class ContextOne : DbContext 
{ 
    public DbSet<Model_One1> 
    public DbSet<Model_One2> 
} 

public class ContextTwo : DbContext 
{ 
    public DbSet<Model_Two1> 
    public DbSet<Model_Two2> 
} 

public class ContextThree : DbContext 
{ 
    public DbSet<Model_Three1> 
    public DbSet<Model_Three2> 
} 

public interface IRepository<T> where T : DbContext 
{ 
    void Add<T>(T entity) where T : class; 
} 

public class Repository<T> where T : DbContext 
{ 
    void Add<T>(T entity) where T : class 
    { 
     //T is DbContext and Model. So confusing 
    } 
} 

public interface IUnitOfWork<IRepository> 
{ 
} 

public class UnitOfWork<IRepository> 
{ 
    //IRepository contains more than one DbContext how can I initiate them here? 
} 

//in application should look like this 
public class BaseController : Controller 
{ 
    protected IRepository repository = new .. //here I have no idea with multiple DbContext 
} 

public class HomeController : BaseController 
{ 
    public ActionResult Add(Model_Two2 model) 
    { 
     base.repository.Add<Model_Two2>(model) 
    } 
} 

Wenn ich die IRepository und IUnitOfWork von Controller-Aufruf, wie kann ich den passenden Kontext wissen? Was ist die beste Vorgehensweise für dieses Problem?

Antwort

6

Ich würde Ihnen vorschlagen UnitOfWork Muster mit einem Constructor-Parameter erstellen DbContext zu akzeptieren -

public class UnitOfWork : IUnitOfWork 
{ 
    private readonly IDbContext _context; 

    private bool _disposed; 
    private Hashtable _repositories; 

    public UnitOfWork(IDbContext context) 
    { 
     _context = context; 
    } 

    public void Dispose() 
    { 
     Dispose(true); 
     GC.SuppressFinalize(this); 
    } 

    public void Save() 
    { 
     _context.SaveChanges(); 
    } 

    public virtual void Dispose(bool disposing) 
    { 
     if (!_disposed) 
      if (disposing) 
       _context.Dispose(); 

     _disposed = true; 
    } 

    public IRepository<TEntity> Repository<TEntity>() where TEntity : class 
    { 
     if (_repositories == null) 
      _repositories = new Hashtable(); 

     var type = typeof(TEntity).Name; 

     if (_repositories.ContainsKey(type)) return (IRepository<TEntity>) _repositories[type]; 

     var repositoryType = typeof (Repository<>); 

     var repositoryInstance = 
      Activator.CreateInstance(repositoryType 
       .MakeGenericType(typeof (TEntity)), _context); 

     _repositories.Add(type, repositoryInstance); 

     return (IRepository<TEntity>) _repositories[type]; 
    } 
} 

wo IDbContext ist -

public interface IDbContext 
{ 
    IDbSet<T> Set<T>() where T : class; 
    int SaveChanges(); 
    void Dispose(); 
} 

Und das Repository Implementierung wäre -

public class Repository<TEntity> : IRepository<TEntity> where TEntity : class 
    { 
     internal IDbContext Context; 
     internal IDbSet<TEntity> DbSet; 

     public Repository(IDbContext context) 
     { 
      Context = context; 
      DbSet = context.Set<TEntity>(); 
     } 

     public virtual TEntity FindById(object id) 
     { 
      return DbSet.Find(id); 
     } 

     public virtual void Update(TEntity entity) 
     { 
      DbSet.Attach(entity); 
     } 
     public virtual void Delete(object id) 
     { 
      var entity = DbSet.Find(id); 
      var objectState = entity as IObjectState; 
      if (objectState != null) 
       objectState.State = ObjectState.Deleted; 
      Delete(entity); 
     } 

     public virtual void Delete(TEntity entity) 
     { 
      DbSet.Attach(entity); 
      DbSet.Remove(entity); 
     } 

     public virtual void Insert(TEntity entity) 
     { 
      DbSet.Attach(entity); 
     } 

     public virtual List<TEntity> GetAll() 
     { 
      return DbSet.ToList(); 
     } 
    } 

Mit diesem Ansatz können Sie eine UnitOfWork für einzelne DBContext erstellen und Sie haben eine bestimmte Logik zum Festschreiben oder Rollback in UnitOfWork.

+0

Wie soll ich das IRepository und IUnitOfWork in meinem BaseController aufrufen? Sollte ich für jedes Modell Hunderte von IRepository-Instanzen erstellen? Zum Beispiel: IRepository repositoryStudent = neues Repository () 'etc, etc. – derodevil

+0

Ich glaube nicht, dass' BaseController' der richtige Ort wäre, um eine UoW zu initiieren. Stattdessen sollte es auf Anfrage auf der Ebene Ihres Geschäftsprozesses erstellt werden. Erstellen Sie daher spezifische UOW basierend auf DbContexts nach Bedarf und erhalten Sie dann spezifische Repositories. – ramiramilu

+0

Da Ihr 'UnitOfWork' keinen Destruktor und keine verwalteten Ressourcen hat, müssen Sie' GC.SuppressFinalize (this) 'nicht aufrufen und müssen kein Dispose-Pattern implementieren. Sie müssen nur '_context.Dispose()' in 'UnitOfWork.Dispose' aufrufen – Albert

0

Ich würde implementieren UnitOfWork als ActionAttribute wo OnActionExecuting ich Transaktion öffnen und OnActionExecuted Ich verpflichte Transaktion, wenn alles in Ordnung ist, wenn Ausnahme in ActionContext ist, sollte Transaktion rückgängig gemacht werden.

Das Problem ist, dass Sie 2 DbContexte haben. Ich denke, Sie sollten faul Kreation von dbContexts haben. Führen Sie eine Art Flag-Variable ein und setzen Sie sie auf True in UnitOfWork.OnActionExecuting. Wenn Sie dbContext das erste Mal berühren, sollten Sie überprüfen, ob Sie mit UnitOfWork umgehen, und wenn ja, sollten Sie die Transaktion für diesen bestimmten dbContext öffnen. Alle offenen Transaktionen können in eine Liste eingetragen werden, die unter UnitOfWork.ActionExecuted erreichbar ist. Überprüfen Sie abschließend, ob in ActionContext Ausnahmen vorhanden sind: ja - Rollback, no - Commit.

+0

Kein Problem für Commit und Rollback-Transaktion. Ich brauche eine Erklärung über die beste Vorgehensweise zum Erstellen von Repsitory- und UoW-Mustern mit mehreren DbContext, da sich meine Anwendung mit mehreren Datenbanken auf demselben und verschiedenen Servern verbinden muss. Ich möchte, dass eine einzelne UOW mit einem einzigen generischen Repository diese DbContexte verarbeiten kann. – derodevil

Verwandte Themen