2010-11-28 12 views
31

Neu bei EF und ich habe bemerkt, dass ein Repository-Muster mit wirklich die Dinge vereinfachen kann und wird mir erlauben, einige spöttische too.So weit, so gut zu tun.Repository-Muster im Entity-Framework 4 Wann sollten wir disponieren?

Meine Frage

Eine typische Anwendung des Object ist so bald wie möglich zu zerstören, siehe unten

using (var context = new SchoolEntities()) 
{  
    context.AddToDepartments(department);  
    context.SaveChanges(); 
} 

das Repository-Muster verwendet Ich habe bemerkt, dass niemand wirklich nutzt die „Verwendung von Pattern“ zB

Sollte die Idee sein, dass wir den Kontext so schnell wie möglich beseitigen sollten, sonst könnte der Speicher auslaufen oder sehr groß werden?

Kann mir jemand erklären? Danke vielmals.

Antwort

47

Ja, Sie sollten den Kontext auch dann verwerfen, wenn Sie das Repository verwenden. Es ist nicht klar, welchen Vorteil Ihre Repository-Implementierung Ihnen gibt, weil Sie immer noch ObjectContext als Konstruktorparameter angeben, nicht wahr?

IMO der Hauptgrund für die Verwendung von Repository und benutzerdefinierte UnitOfWork ist Persistenz Ignoranz = Hidding EF-Code von oberen Anwendungsschichten, da ObjectContext + ObjectSet selbst sind die Implementierung von Repository und Arbeitseinheit Muster.

Wenn ich Repository bin mit, ich bin Umwickeln immer ganzen EF-Code, so dass die öffentliche Schnittstelle meines Repository bietet keine Informationen über EF bezogene Infrastruktur. In diesem Fall liegt es an mir, wie ich mit ObjectContext umgehen kann.

Für eine einfache geradeaus CRUD Szenarien kann ich Kontext Schaffung wickeln und in jedem Repository Verfahren entsorgen. In komplexeren Szenarien verwende ich eine zusätzliche Klasse - UnitOfWork (UoW), die das Erstellen und Löschen von Kontexten umschließt und das Speichern von Änderungen in der Datenbank auslöst. Es fungiert auch als Factory für alle Repositorys und übergibt die Instanz des erstellten Kontexts an die Konstruktoren der Repositorys.

Die meiste Zeit ich Dienste oder Web-Anwendungen bin Programmierung so dass ich mit abgesetzter Objekte zu tun habe. Ich verwende immer eine einzelne UoW-Instanz für die Anfrageverarbeitung. Daher wird die UoW zu Beginn der Anforderungsverarbeitung erstellt und am Ende der Anforderungsverarbeitung freigegeben. Im Fall von WinForms/WPF-Anwendungen und die angeschlossenen Objekten denke ich, die gute Idee ist UOW/Object Instanz „pro Form“ zu haben - es gibt article beschreiben diesen Ansatz mit NHibernate-Sitzung (wie bei EF Object) in MSDN Magazin.

Einige Start-Implementierung von UnitOfWork und Repository-Muster:

Inhaber Kontext und abstrakten Werk für Endlager

public interface IUnitOfWork 
{ 
    IRepository<MyEntity> MyEntityRepository { get; } 
    // Repositories for other entities 

    SaveChanges(); 
} 

Repository für freistehende Einheiten

public interface IRepository<T> where T : class 
{ 
    IQueryable<T> GetQuery(); 
    void Insert(T entity); 
    void Delete(T entity); 

    // In very complex scenarios with big object graphs you will probably give up 
    // using detached approach and you will always load your entities from DB before 
    // deleting or updating them. In such case you will not need Update method at all. 

    void Update(T entity); 
} 

Einweg-Implementierung von UnitOfWork Enitity Rahmen Einwickeln

public class UnitOfWork : IUnitOfWork, IDisposable 
{ 
    private ObjectContext _context = null; 

    public UnitOfWork(string connectionString) 
    { 
    if (String.IsNullOrEmpty(connectionString)) throw new ArgumentNullException("connectionString"); 
    _context = new ObjectContext(connectionString); 
    } 

    private IRepository<MyEntity> _myEntityRepository; 

    public IRepository<MyEntity> MyEntityRepository 
    { 
    get 
    { 
     return _myEntityRepository ?? (_myEntityRepository = new GeneralRepository<MyEntity>(_context)); 
    } 
    } 

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

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

    protected virtual void Dispose(bool disposing) 
    { 
    if (disposing) 
    { 
     if (_context != null) 
     { 
     _context.Dispose(); 
     _context = null; 
     } 
    } 
    } 
} 

Base-Repository Implementierung

public class GeneralRepository<T> : IRepository<T> where T : class 
{ 
    private ObjectSet<T> _set; 
    private ObjectContext _context; 


    public GeneralRepository(ObjectContext context) 
    { 
    if (context == null) throw new ArgumentNullException("context"); 
    _context = context; 
    _set = context.CreateObjectSet<T>(); 
    } 

    // Override this method for example if you need Includes 
    public virtual IQueryable<T> GetQuery() 
    { 
    return _set; 
    } 

    // Override following methods if you are working with object graphs. 
    // Methods do not execute operations in database. It is responsibility of 
    // UnitOfWork to trigger the execution 

    public virtual void Insert(T entity) 
    { 
    if (entity == null) throw new ArgumentNullException("entity"); 
    _set.AddObject(entity); 
    } 

    // These impelementations are for detached scenarios like web application 

    public virtual void Delete(T entity) 
    { 
    if (entity == null) throw new ArgumentNullException("entity"); 
    _set.Attach(entity); 
    _set.DeleteObject(entity); 
    } 

    public virtual void Update(T entity) 
    { 
    if (entity == null) throw new ArgumentNullException("entity"); 
    _set.Attach(entity); 
    _context.ObjectStateManager.ChangeObjectState(entity, EntityState.Modified); 
    } 
} 

Verwendung, wenn Daten

using (var uow = new UnitOfWork(connectionString)) 
{ 
    var entity = uow.MyEntitiesRepository.GetQuery().Single(e => e.Id == 1); 
    // Do something with entity 
} 

Verwendung ausgewählt wird, wenn Daten

using (var uow = new UnitOfWork(connectionString)) 
{ 
    uow.MyEntitiesRepository.Update(entity); 
    uow.SaveChanges(); 
} 
+1

Fantastic.Thanks modifing !!! Das einzige Problem, das ich mit diesen Repositories habe, ist, dass keiner von ihnen das Eager-Laden von "Include" behandelt. Wie machst du mit deinem Repository ein eifriges Laden? – user9969

+1

Das ist der schwierige Teil, denn Include ist Feature von EF ObjectQuery. Ich erstelle normalerweise ein geerbtes Repository von GeneralRepository und füge notwendige Includes in überschriebene GetQuery ein. Aber wenn Sie nur für einige Abfragen das eifrige Laden aktivieren müssen, wird es Ihnen nicht helfen. In diesem Fall brauchen Sie etwas anderes. Ich kann mir vorstellen, etwas wie LoadOptions von Linq-To-Sql zu implementieren und diese Optionen in UnitOfWork oder Repository zu übergeben. Verwenden Sie dann optins, um alle Includes zu setzen. –

+2

Sehr detaillierte Antwort - Ihre 'UnitOfWork'-Klasse verfügt jedoch über eine einzige' IRepository'-Instanz mit lokalem Bereich, was bedeutet, dass die Unit of Work das Repository definiert, mit dem gearbeitet werden soll. Das ist nicht richtig. Der Zweck der Unit of Work besteht darin, Transaktionen über mehrere Repositories hinweg zu verwalten (die UoW akzeptiert in der Regel 1- * Repositories über ihren ctor). Mit dieser Implementierung geht das überhaupt nicht um. Vielleicht ist das für das OP gut. – RPM1984

Verwandte Themen