Qu’est-ce qu’un repository IR et à quoi sert-il?

Qu’est-ce qu’un IRepository? Pourquoi est-il utilisé, des exemples simples et brefs ne feront pas mal.

MVC favorise la séparation des préoccupations, mais cela ne s’arrête pas au niveau MVC.

L’access aux données est une préoccupation en soi. Cela devrait être fait dans le bit M de MVC, c’est-à-dire le modèle. La structure de votre modèle dépend de vous, mais les gens suivent généralement des schémas éprouvés (pourquoi réinventer la roue?). Le modèle de référentiel est la norme actuelle. Cependant, ne vous attendez pas à une formule simple, car les variantes sont presque identiques à celles des développeurs.

IRepository est simplement une interface que vous créez (elle ne fait pas partie de MVC ou ASP.NET ou .NET). Il vous permet de “découpler” vos référentiels des implémentations réelles. Le découplage est bon car cela signifie votre code …:

  1. Votre code est beaucoup plus réutilisable. C’est tout simplement bien.
  2. Votre code peut utiliser Inversion of Control (ou Dependency Injection). C’est bien de garder vos préoccupations bien séparées. C’est particulièrement bien parce que cela permet aux tests unitaires …
  3. Votre code peut être testé à l’unité. Ceci est particulièrement utile dans les grands projets avec des algorithmes complexes. C’est bon partout, car cela augmente votre compréhension des technologies avec lesquelles vous travaillez et des domaines que vous essayez de modéliser dans un logiciel.
  4. Votre code s’articule autour des meilleures pratiques, selon un schéma commun. C’est bien parce que cela facilite beaucoup la maintenance.

Donc, après avoir vendu votre découplage, la réponse à votre question est que IRepository est une interface que vous créez et dont vous faites hériter vos référentiels. Cela vous donne une hiérarchie de classe fiable pour travailler.

J’utilise généralement un IRepository générique. C’est à dire:

IRépositoire

Où Tentity est, eh bien, une entité. Le code que j’utilise est:

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace Wingspan.Web.Mvc { public interface IRepository where TEntity : class { List FetchAll(); IQueryable Query {get;} void Add(TEntity entity); void Delete(TEntity entity); void Save(); } } 

Une implémentation concrète de cette interface serait:

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data.Linq; using Wingspan.Web.Mvc; namespace ES.eLearning.Domain { public class SqlRepository : IRepository where T : class { DataContext db; public SqlRepository(DataContext db) { this.db = db; } #region IRepository Members public IQueryable Query { get { return db.GetTable(); } } public List FetchAll() { return Query.ToList(); } public void Add(T entity) { db.GetTable().InsertOnSubmit(entity); } public void Delete(T entity) { db.GetTable().DeleteOnSubmit(entity); } public void Save() { db.SubmitChanges(); } #endregion } } 

Cela me permet d’écrire:

 SqlRepository UserCoursesRepository = new SqlRepository(db); 

Où db est une instance DataContext injectée dans, par exemple, un service.

Avec UserCoursesRepository, je peux maintenant écrire des méthodes dans ma classe de service comme:

 public void DeleteUserCourse(int courseId) { var uc = (UserCoursesRepository.Query.Where(x => x.IdUser == UserId && x.IdCourse == courseId)).Single(); UserCoursesRepository.Delete(uc); UserCoursesRepository.Save(); } 

Et maintenant, dans mes contrôleurs, je peux simplement écrire:

 MyService.DeleteUserCourse(5); MyService.Save(); 

C’est-à-dire que le développement de votre application devient davantage une chaîne de assembly qui mène à un contrôleur TRÈS simple. Chaque pièce de la chaîne de assembly peut être testée indépendamment de tout le rest, ainsi les bugs sont pincés dans l’œuf.

S’il s’agit d’une réponse longue et lourde, c’est parce que la vraie réponse est:

Achetez le livre Framework de ASP.NET MVC 2 de Steven Sanderson et apprenez à penser dans MVC.

Un IRepository est une interface que vous spécifiez lorsque vous souhaitez implémenter le modèle de référentiel. Comme @Brian Ball l’a déclaré, il ne fait pas partie de .NET, c’est une interface que vous créez.

Les développeurs utilisant le modèle de référentiel recommandent généralement l’utilisation d’une interface pour la mise en œuvre. Par exemple, dans l’application que je développe actuellement, j’ai 5 référentiels. 4 spécifiques et 1 générique. Chacune hérite d’un IRepository ce qui IRepository que les IRepository d’ IRepository ne seront pas résolus.

En ce qui concerne les exemples de code, je vais essayer:

 interface IRepository where T : class { IQueryable Select(); } 

Implémenté en tant que référentiel générique:

 public class Repository : IRepository where T : class { public IQueryable Select() { return this.ObjectContext.CreateObjectSet(); } } 

Mis en œuvre en tant que référentiel spécialisé:

 public class EmployeeRepository : IRepository { public IQueryable Select() { return this.ObjectContext.Employees; } } 

Le Repository et EmployeeRepository implémentent IRepository , mais ils effectuent les requêtes légèrement différemment. Le référentiel générique doit créer un ensemble d’objects de T avant de pouvoir essayer quoi que ce soit.

N’oubliez pas que le Repository est censé être verrouillé sur l’interface, où EmployeeRepository peut implémenter des méthodes plus spécialisées pour réaliser une logique plus complexe.

J’espère que cela vous aide un peu.

Un référentiel est une abstraction qui représente tout magasin de données sous-jacent et arbitraire comme s’il s’agissait d’une collection d’objects en mémoire .

Cette définition est transformée en une forme plus pratique en raison de pratiques courantes et de limitations système, en tant que collection d’objects en mémoire représentant un magasin de données sous-jacent et arbitraire, éventuellement déconnecté . Sous le capot, le référentiel peut être lié à une firebase database, à un fichier plat, à une collection d’objects en mémoire ou à tout ce que vous pouvez imaginer. L’utilisateur d’un référentiel s’en fiche.

Ainsi, un IRepository est le contrat d’interface qui définit comment le code Api souhaite que le code client interagisse avec le référentiel. Cela inclut souvent les contrats d’ajout, de mise à jour, de suppression et d’obtention de contrats, comme par exemple cet exemple très courant de contrat de référentiel:

 public interface IRepository where TEntity : class { List GetAll(); void Add(TEntity entity); void Delete(TEntity entity); void Save(); } 

Mais je préfère utiliser une interface différente pour plusieurs raisons.

Tout d’abord, vous n’utiliserez généralement pas de référentiel lui-même, vous l’utiliserez probablement avec un modèle d’unité de travail. Le référentiel ne devrait donc pas avoir de méthode Save (). Il pourrait avoir une méthode de Update(T entity) – mais pourquoi? L’object que vous recevez du référentiel sera automatiquement modifiable / mis à jour, comme tout autre object que vous recevriez de n’importe quel type de collection d’objects, car vous avez récupéré des références aux objects eux-mêmes. (Par exemple: si votre TEntity est un object Person et que vous obtenez la personne “Chuck” et que vous modifiez son nom de famille de “Bartowski” en “Carmichael”, le référentiel a probablement déjà mis à jour ladite entité. Si cela semble ténu dans votre l’esprit, il n’y a rien de mal à mettre en œuvre une méthode Update(T entity) .)

Deuxièmement, la plupart des référentiels devraient être capables de gérer des environnements déconnectés. Si votre solution ne comporte pas cette exigence, vous pouvez toujours créer une interface qui gère les scénarios déconnectés et la laisser simplement non implémentée. Maintenant, vous êtes prêt pour l’avenir.

Enfin, notre contrat a plus de sens pour la véritable nature d’un référentiel – un ensemble d’objects en mémoire représentant un magasin de données arbitraire, éventuellement déconnecté .

 public interface IRepository where TEntity : class { List GetAll(); List Get(Func where); void Insert(TEntity entity); void Insert(IEnumerable entities); void Remove(TEntity entity); void Remove(IEnumerable entities); void SyncDisconnected(TEntity entity, bool forDeletion = false); void SyncDisconnected(IEnumerable entities, bool forDeletion = false); } 

Si vous définissez une classe de base pour toutes vos entités, appelons-la DomainObject et atsortingbuez-lui un champ Id . Vous pouvez alors procéder comme suit:

 public interface IRepository where TEntity : DomainObject { TEntity GetById(object Id); List GetAll(); List Get(Func where); void Insert(TEntity entity); void Insert(IEnumerable entities); void Remove(TEntity entity); void Remove(IEnumerable entities); void SyncDisconnected(TEntity entity, bool forDeletion = false); void SyncDisconnected(IEnumerable entities, bool forDeletion = false); } 

Si vous n’aimez pas le paramètre optionnel forDeletion , vous pouvez append une méthode permettant également de synchroniser des objects supprimés:

  void SyncDisconnectedForDeletion(TEntity entity); 

Cela est dû au fait que, dans la plupart des cas, la synchronisation d’objects supprimés pour la suppression est incompatible avec la synchronisation d’objects ajoutés pour l’ajout ou la modification. (Essayez-le. Vous verrez par vous-même que les exigences en matière de suppression d’un magasin varient énormément de celles d’addition ou de modification). Par conséquent, l’interface doit définir un contrat afin que l’implémentation puisse faire la distinction entre les deux.

Vous pouvez implémenter cette interface sur TOUS les référentiels de TOUT magasin de données sous-jacent, connecté ou déconnecté, y compris d’autres abstractions de magasins de données sous-jacents tels qu’Entity Framework.

IRepository n’est pas un type défini dans le framework .Net. Habituellement, lorsque vous voyez une interface nommée ainsi, le programme utilise le modèle de référentiel ( https://web.archive.org/web/20110503184234/http://blogs.hibernatingrhinos.com/nhibernate/archive/2008/10/08/ le-repository-pattern.aspx ). Généralement, lorsque les utilisateurs utilisent ce modèle, ils créent une interface à laquelle adhèrent tous les référentiels. Cela présente de nombreux avantages. Certains des avantages sont le découplage de code et les tests unitaires.

Il est également courant que cela soit fait pour pouvoir en tirer parti avec IoC ( http://en.wikipedia.org/wiki/Inversion_of_control ).