Pour retourner IQueryable ou ne pas retourner IQueryable

J’ai une classe de référentiel qui encapsule mon contexte de données LINQ to SQL. La classe de référentiel est une classe de ligne de gestion qui contient toute la logique du niveau de données (et la mise en cache, par exemple).

Voici mon v1 de mon interface repo.

public interface ILocationRepository { IList FindAll(); IList FindForState(State state); IList FindForPostCode(ssortingng postCode); } 

Mais pour gérer la pagination pour FindAll, je me demande s’il faut ou non exposer IQueryable au lieu d’IList pour simplifier l’interface pour des circonstances telles que la pagination.

Quels sont les avantages et les inconvénients de l’exposition de IQueryable à partir du repository de données?

Toute aide est fortement appréciée.

Les pros; composition:

  • les appelants peuvent append des filtres
  • les appelants peuvent append la pagination
  • les appelants peuvent append un sorting
  • etc

Les inconvénients non testabilité:

  • Votre référentiel n’est plus correctement testable; vous ne pouvez pas compter sur un: ça marche, b: ce qu’il fait;
    • l’appelant pourrait append une fonction non traduisible (c.-à-d. pas de mappage TSQL, de pauses à l’exécution)
    • l’appelant peut append un filtre / sorting qui le fait fonctionner comme un chien
  • Comme les appelants s’attendent à ce que IQueryable soit composable, ils excluent les implémentations non composables – ou vous obligent à écrire votre propre fournisseur de requêtes.
  • cela signifie que vous ne pouvez pas optimiser / profiler le DAL

Pour la stabilité, je me suis engagé à ne pas exposer IQueryable ou Expression<...> sur mes référentiels. Cela signifie que je sais comment se comporte le référentiel et que mes couches supérieures peuvent utiliser des simulacres sans se soucier “le référentiel actuel supporte-t-il cela?” (forçant les tests d’intégration).

J’utilise toujours IQueryable etc dans le référentiel – mais pas au-delà des limites. J’ai posté d’ autres reflections sur ce thème ici . Il est tout aussi simple de mettre des parameters de pagination sur l’interface du référentiel. Vous pouvez même utiliser des méthodes d’extension (sur l’interface) pour append des parameters de pagination optionnels , de sorte que les classes concrètes ne disposent que d’une méthode à implémenter, mais il peut y avoir 2 ou 3 surcharges disponibles pour l’appelant.

Comme mentionné dans la réponse précédente, exposer IQueryable donne access aux appelants pour jouer avec IQueryable lui-même, ce qui est ou peut devenir dangereux.

Encapsuler la première responsabilité de la logique métier consiste à maintenir l’intégrité de votre firebase database.

Vous pouvez continuer à exposer IList et modifier vos parameters comme suit, voici comment nous procédons …

 public interface ILocationRepository { IList FindAll(int start, int size); IList FindForState(State state, int start, int size); IList FindForPostCode(ssortingng postCode, int start, int size); } 

si taille == -1 alors retournez tout …

Manière alternative …

Si vous voulez toujours retourner IQueryable, vous pouvez retourner IQueryable of List dans vos fonctions .. par exemple …

 public class MyRepository { IQueryable FindAll() { List myLocations = ....; return myLocations.AsQueryable; // here Query can only be applied on this // subset, not directly to the database } } 

La première méthode a un avantage sur la mémoire, car vous retournerez moins de données au lieu de toutes.

Je recommande d’utiliser IEnumerable au lieu de IList , avec cela vous aurez plus de flexibilité.

De cette façon, vous ne pourrez obtenir de Db que la partie des données que vous utiliserez réellement sans travail supplémentaire dans votre référentiel.

Échantillon:

 // Repository public interface IRepository { IEnumerable GetLocations(); } // Controller public ActionResult Locations(int? page) { return View(repository.GetLocations().AsPagination(page ?? 1, 10); } 

Ce qui est super propre et simple.