Oui, vous devez disposer du contexte même si vous utilisez le référentiel. L'avantage que vous apporte votre implémentation de Repository n'est pas clair car vous fournissez toujours ObjectContext en tant que paramètre du constructeur, n'est-ce pas? IMO la principale raison de l'utilisation de Repository et UnitOfWork personnalisé est la persistance ignorance = hidding EF code des couches supérieures de l'application car ObjectContext + ObjectSet eux-mêmes sont la mise en œuvre des modèles de référentiel et d'unité de travail.
Si j'utilise le référentiel, j'enveloppe toujours le code EF entier, donc l'interface publique de mon référentiel ne fournit aucune information sur l'infrastructure EF. Dans ce cas, c'est à moi de décider comment je gère ObjectContext. Pour des scénarios CRUD simples et faciles, je peux intégrer la création de contexte et la disposition dans chaque méthode de référentiel. Dans des scénarios plus complexes, j'utilise une classe supplémentaire - UnitOfWork (UoW), qui enveloppe la création et l'élimination du contexte et déclenche l'enregistrement des modifications dans la base de données. Il agit également comme usine pour tous les référentiels et transmet l'instance du contexte créé dans les constructeurs de référentiels.
La plupart du temps, je suis en train de programmer des services ou des applications web, donc j'ai affaire à des objets détachés. J'utilise toujours une instance unique pour le traitement des demandes. Ainsi, l'UoW est créée au début du traitement des demandes et libérée à la fin du traitement de la demande. Dans le cas des applications WinForms/WPF et des objets attachés je pense que la bonne idée est d'avoir UoW / ObjectContext instance "par formulaire" - il y a article décrivant cette approche avec NHibernate session (même que EF ObjectContext) dans le magazine MSDN.
Certains commencer la mise en œuvre de UnitOfWork et modèles du référentiel:
titulaire du contexte et de l'usine abstraite pour les dépôts
public interface IUnitOfWork
{
IRepository<MyEntity> MyEntityRepository { get; }
// Repositories for other entities
SaveChanges();
}
Repository pour les entités individuelles
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);
}
mise en œuvre jetable de UnitOfWork emballage cadre Enitity
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;
}
}
}
}
mise en œuvre du référentiel de base
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);
}
}
d'utilisation lors de la sélection des données
using (var uow = new UnitOfWork(connectionString))
{
var entity = uow.MyEntitiesRepository.GetQuery().Single(e => e.Id == 1);
// Do something with entity
}
Utilisation des données lorsque modifing
using (var uow = new UnitOfWork(connectionString))
{
uow.MyEntitiesRepository.Update(entity);
uow.SaveChanges();
}
Fantastic.Thanks !!! Le seul problème que j'ai avec ces dépôts est qu'aucun d'entre eux ne gère le chargement "Inclure". Comment faites-vous le chargement passionné avec votre référentiel? – user9969
C'est la partie difficile, car Inclure est une fonctionnalité de EF ObjectQuery. Je crée généralement un référentiel hérité à partir de GeneralRepository et j'ajoute les Include nécessaires dans overriden GetQuery. Mais si vous avez besoin d'activer le chargement impatient pour certaines requêtes, cela ne vous aidera pas. Dans ce cas, vous avez besoin d'autre chose. Je peux imaginer implémenter quelque chose comme LoadOptions de Linq-To-Sql et passer ces options dans UnitOfWork ou Repository. Puis, en utilisant optins pour définir tout inclut. –
Réponse très complète - cependant, votre classe 'UnitOfWork' a une seule instance' IRepository 'de portée locale, ce qui signifie que l'unité de travail définit le référentiel avec lequel travailler. Ce n'est pas correct. Le but de l'unité de travail est de gérer les transactions entre plusieurs référentiels (le logiciel accepte généralement les dépôts 1- * via son ctor). Cette implémentation ne gère pas vraiment cela du tout. Peut-être que c'est bien pour l'OP si. – RPM1984