73 votes

Pour retourner IQueryable <T> ou ne pas retourner IQueryable <T>

J'ai un référentiel de classe qui encapsule mon LINQ to SQL Contexte de Données. Le référentiel de la classe est un métier de classe qui contient toutes les données de niveau logique (et la mise en cache et tel).

Voici mon v1 de mon repo interface.

public interface ILocationRepository
{
    IList<Location> FindAll();
    IList<Location> FindForState(State state);
    IList<Location> FindForPostCode(string postCode);
}

Mais pour gérer la pagination pour FindAll, je suis débats à savoir si ou de ne pas exposer IQueryable<ILocation> au lieu de IList de simplifier l'interface pour des circonstances telles que la pagination.

Quels sont les avantages et les inconvénients d'exposer IQueryable à partir des données repo?

Toute aide est très appréciée.

90voto

Marc Gravell Points 482669

Les pros; la composabilité:

  • les appelants peuvent ajouter des filtres
  • les appelants peuvent ajouter la pagination
  • les appelants peuvent ajouter un tri
  • etc

Les inconvénients; la non-réfutabilité:

  • Le référentiel n'est plus correctement unité vérifiable; vous ne pouvez pas compter sur un: il travaille, b: ce qu' il fait;
    • l'appelant pourrait ajouter un non-traduisible fonction (c'est à dire pas de TSQL de cartographie, des pauses au moment de l'exécution)
    • le visiteur pourrait ajouter un filtre/tri qui le fait travailler comme un chien
  • Depuis les appelants s'attendent IQueryable<T> à être composable, les règles de non-composable implémentations ou il vous oblige à écrire votre propre fournisseur de requêtes pour eux
  • cela signifie que vous ne pouvez pas optimiser / profil de la DAL

Pour la stabilité, j'ai pris pour ne pas exposer IQueryable<T> ou Expression<...> sur mon dépôts. Cela signifie que je sais comment le référentiel de se comporter, et mes couches supérieures pouvez utiliser les objets fantaisie, sans se soucier de "l'référentiel de soutien?" (forcer les tests d'intégration).

- Je encore utiliser IQueryable<T> etc à l'intérieur du référentiel - mais pas sur la limite. J'ai posté quelques idées sur ce thème ici. Il est tout aussi facile de mettre les paramètres de pagination sur le référentiel de l'interface. Vous pouvez même utiliser des méthodes d'extension (sur l'interface) à ajouter en option des paramètres de pagination, de sorte que les classes concrètes ont seulement 1 méthode à mettre en œuvre, mais il y a peut être 2 ou 3 surcharges disponible à l'appelant.

7voto

Akash Kava Points 18026

Comme l'a mentionné à la réponse précédente, exposant IQueryable donne accès aux appelants de jouer avec IQueryable lui-même, qui est ou peut devenir dangereux.

L'encapsulation de la logique métier de première responsabilité est de maintenir l'intégrité de votre base de données.

Vous pouvez continuer à exposer IList et peut-être modifier vos paramètres suivants, c'est la façon dont nous sommes en train de faire...

public interface ILocationRepository
{
    IList<Location> FindAll(int start, int size);
    IList<Location> FindForState(State state, int start, int size);
    IList<Location> FindForPostCode(string postCode, int start, int size);
}

si la taille de l' == -1 alors retour tous les...

Autre façon...

Si vous voulez encore de retour IQueryable, alors vous pouvez retourner IQueryable de la Liste à l'intérieur de vos fonctions.. par exemple...

public class MyRepository
{
    IQueryable<Location> FindAll()
    {
        List<Location> myLocations = ....;
        return myLocations.AsQueryable<Location>;
        // 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, parce que vous reviendra moins de données à la place de tous.

2voto

Konstantin Tarkus Points 16862

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 portion de données que vous utiliserez réellement sans travail supplémentaire dans votre référentiel.

Échantillon:

 // Repository
public interface IRepository
{
    IEnumerable<Location> GetLocations();
}

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

Ce qui est super propre et simple.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X