J'ai une classe de référentiel qui enveloppe mon LINQ to SQL Data Context. La classe de référentiel est une classe de ligne métier qui contient toute la logique de la couche de données (et la mise en cache, etc.).
Voici ma v1 de mon interface repo.
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 me demande s'il faut ou non exposer IQueryable <ILocation> au lieu de IList pour simplifier l'interface dans des circonstances telles que la pagination.
Quels sont les avantages et les inconvénients d'exposer IQueryable à partir du référentiel de données?
Toute aide est fortement appréciée.
Les avantages; composabilité:
Les inconvénients; non-testabilité:
IQueryable<T>
pour être composable, cela exclut les implémentations non composables - ou il vous oblige à écrire votre propre fournisseur de requêtes pour ellesPour la stabilité, j'ai pris pour pas exposer IQueryable<T>
ou Expression<...>
sur mes référentiels. Cela signifie que je sais comment le référentiel se comporte et que mes couches supérieures peuvent utiliser des simulations sans se soucier "est-ce que le référentiel actuel prend en charge cela?" (forcer les tests d'intégration).
J'utilise toujours IQueryable<T>
etc à l'intérieur le référentiel - mais pas au-dessus de la limite. J'ai posté quelques plus de réflexions sur ce thème ici . Il est tout aussi simple de mettre des paramètres de pagination sur l'interface du référentiel. Vous pouvez même utiliser des méthodes d'extension (sur l'interface) pour ajouter des paramètres de pagination optionnel, afin que les classes concrètes n'aient qu'une seule 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 accès aux appelants pour jouer avec IQueryable lui-même, ce qui est ou peut devenir dangereux.
La première responsabilité d'encapsuler la logique métier est de maintenir l'intégrité de votre base de données.
Vous pouvez continuer à exposer IList et modifier vos paramètres comme suit, c'est ainsi que nous faisons ...
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 taille == -1 alors renvoie tout ...
Voie alternative ...
Si vous souhaitez toujours retourner IQueryable, vous pouvez renvoyer IQueryable de List dans 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, car vous retournerez moins de données au lieu de tout.
Je recommande d'utiliser IEnumerable
au lieu de IList
, avec elle, vous aurez plus de flexibilité.
De cette façon, vous ne pourrez obtenir de Db que la partie des données que vous utiliserez vraiment sans travail supplémentaire effectué dans votre référentiel.
// 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.