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();
}
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
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. –
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