71 votes

Différences entre IQueryable, List, IEnumerator?

Je me demande quelle est la différence entre IQueryable, List, IEnumerator et quand dois-je les utiliser?

Par exemple, lorsque vous utilisez linq to sql, je ferais quelque chose comme ceci

 public List<User> GetUsers()
{
   return db.User.where(/* some query here */).ToList();
}
 

Je me demande maintenant si je devrais utiliser IQueryable à la place, mais je ne suis pas sûr des avantages de l’utiliser sur la liste.

126voto

Adam Robinson Points 88472

IQueryable<T> est destiné à permettre à un fournisseur de requêtes (par exemple, un ORM comme LINQ to SQL ou Entity Framework) d'utiliser les expressions contenues dans une requête pour traduire la demande dans un autre format. En d'autres termes, LINQ-to-SQL regarde les propriétés sur les entités que vous utilisez avec les comparaisons que vous faites et crée en fait une instruction SQL express (espérons-le) d'un montant équivalent de la demande.

IEnumerable<T> est plus générique que l' IQueryable<T> (bien que toutes les instances de l' IQueryable<T> œuvre IEnumerable<T>) et seulement définit une séquence. Cependant, il existe des méthodes d'extension disponibles au sein de l' Enumerable classe qui définissent des requêtes de type opérateurs de l'interface et l'utilisation du code ordinaire pour l'évaluation de ces conditions.

List<T> est juste un format de sortie, et alors qu'il implémente IEnumerable<T>, n'est pas directement liée à l'interrogation.

En d'autres termes, lorsque vous utilisez IQueryable<T>, vous êtes à la définition et à l'expression qui se traduit en quelque chose d'autre. Même si vous écrivez du code, ce code n'est jamais exécutée, il ne s' inspecter et de les transformer en quelque chose d'autre, comme un réel requête SQL. De ce fait, que certaines choses ne sont valables que dans ces expressions. Par exemple, vous ne pouvez pas appeler une fonction ordinaire que vous définissez à partir de ces expressions, depuis LINQ-to-SQL ne sais pas comment transformer votre appel dans une instruction SQL. La plupart de ces restrictions ne sont évaluées au moment de l'exécution, malheureusement.

Lorsque vous utilisez IEnumerable<T> pour l'interrogation, vous êtes à l'aide de LINQ-to-Objets, ce qui signifie que vous écrivez le code qui est utilisé pour l'évaluation de votre requête ou de transformer les résultats, il y a donc, en général, pas de restrictions sur ce que vous pouvez faire. Vous pouvez appeler d'autres fonctions au sein de ces expressions librement.

Avec LINQ to SQL

Va de pair avec la distinction ci-dessus, il est également important de garder à l'esprit la façon dont cela fonctionne dans la pratique. Lorsque vous écrivez une requête à l'encontre d'une classe de contexte de données dans LINQ to SQL, il produit un IQueryable<T>. Tout ce que vous faites à l'encontre de l' IQueryable<T> lui-même va se transformer en SQL, donc votre filtrage et transformation sera fait sur le serveur. Tout ce que vous faites à l'encontre de ce que l' IEnumerable<T>, sera fait au niveau de l'application. Parfois, cela est souhaitable (dans le cas où vous avez besoin de faire usage de code côté client, par exemple), mais dans de nombreux cas, ce n'est pas intentionnelle.

Par exemple, si j'avais un contexte avec un Customers propriété représentant une Customer tableau, et chaque client a un CustomerId colonne, regardons deux façons de le faire cette requête:

var query = (from c in db.Customers where c.CustomerId == 5 select c).First();

Ceci va produire SQL qui interroge la base de données pour l' Customer record avec un CustomerId égal à 5. Quelque chose comme:

select CustomerId, FirstName, LastName from Customer where CustomerId = 5

Maintenant, ce qui se passe si nous nous tournons Customers en IEnumerable<Customer> par l'aide de la AsEnumerable() méthode d'extension?

var query = (from c in db.Customers.AsEnumerable() where c.CustomerId == 5 select c).First();

Ce simple changement a une conséquence grave. Puisque nous tournons Customers en IEnumerable<Customer>, cela apportera toute la table et le filtre sur le côté client (bien, strictement parlant, cela va ramener chaque ligne de la table jusqu'à ce qu'il rencontre celle qui s'adapte les critères du programme, mais le point est le même).

ToList()

Jusqu'à présent, nous avons seulement parlé IQueryable et IEnumerable. C'est parce qu'ils sont semblables, des interfaces. Dans les deux cas, vous êtes à la définition d'une requête; qui est, vous êtes définir trouver les données, ce que les filtres à appliquer, et que les données de retour. Ces deux sont des requêtes

query = from c in db.Customers where c.CustomerId == 5 select c;
query = from c in db.Customers.AsEnumerable() where c.CustomerId == 5 select c;

Comme nous en avons parlé, la première requête est à l'aide de IQueryable et la seconde utilise IEnumerable. Dans les deux cas, cependant, c'est juste une requête. La définition de la requête n'est pas réellement rien faire contre la source de données. La requête est exécutée lorsque le code commence à itérer sur la liste. Cela peut se produire de plusieurs façons; un foreach boucle, appelant ToList(), etc.

La requête est exécutée la première et à chaque fois c'est itérée. Si vous vous appelez ToList() sur query deux fois, vous vous retrouvez avec deux listes avec des objets distincts. Ils peuvent contenir les mêmes données, mais ils seraient des références différentes.

Edit après les commentaires

Je veux juste être clair sur la distinction entre le moment où les choses sont en fait côté client et quand ils ont fait côté serveur. Si vous faites référence à un IQueryable<T> comme IEnumerable<T>, seule l'interrogation de fait , après c'est un IEnumerable<T> sera fait côté client. Par exemple, dire que j'ai cette table et une LINQ-to-SQL contexte:

Customer
-----------
CustomerId
FirstName
LastName

J'ai d'abord construire une requête sur la base d' FirstName. Cela crée un IQueryable<Customer>:

var query = from c in db.Customers where c.FirstName.StartsWith("Ad") select c;

Maintenant je passe cette requête à une fonction qui prend un IEnumerable<Customer> et fait de filtrage basé sur LastName:

public void DoStuff(IEnumerable<Customer> customers)
{
    foreach(var cust in from c in customers where c.LastName.StartsWith("Ro"))
    {
        Console.WriteLine(cust.CustomerId);
    }
}

Nous avons fait une deuxième requête ici, mais c'est tout à fait IEnumerable<Customer>. Ce qui se passe ici est que la première requête sera évaluée, l'exécution de cette SQL:

select CustomerId, FirstName, LastName from Customer where FirstName like 'Ad%'

Donc on va ramener tout le monde qui est - FirstName commence par "Ad". Notez qu'il n'y a rien ici à propos de LastName. C'est parce que c'est le filtrage du côté client.

Une fois qu'il ramène ces résultats, le programme va alors effectuer une itération sur les résultats et de les livrer uniquement les enregistrements dont LastName commence par "Ro". L'inconvénient de cette est que nous avons rapporté de données, à savoir, toutes les lignes dont LastName ne pas commencer avec "Ro"--qui pourrait avoir été filtré sur le serveur.

10voto

Femaref Points 41959

IQueryable<T>: les résumés accès de base de données prend en charge l'évaluation différée des requêtes
List<T>: une collection d'entrées. Pas de support de l'évaluation différée
IEnumerator<T>: offre la possibilité de parcourir et d' IEnumerable<T> (dont les deux IQueryable<T> et List<T> le sont)

Le problème avec ce code est très simple - il toujours exécute la requête lorsqu'il est appelé. Si vous retourniez db.User.Where(...) à la place (qui est un IQueryable<T>), vous retenez l'évaluation de la requête jusqu'à ce qu'il est réellement nécessaire (itération). Aussi, si l'utilisateur de cette méthode serait nécessaire de préciser les prédicats, ceux également être exécutée dans la base de données, ce qui le rend plus rapide.

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