De retour IEnumerable<T> vs IQueryable<T>
Quelle est la différence entre le retour IQueryable<T>
vs IEnumerable<T>
?
IQueryable<Customer> custs = from c in db.Customers
where c.City == "<City>"
select c;
IEnumerable<Customer> custs = from c in db.Customers
where c.City == "<City>"
select c;
Seront tous deux mis à exécution différée et quand doit-on être préférée à une autre?
OriginalL'auteur stackoverflowuser | 2010-05-20
Vous devez vous connecter pour publier un commentaire.
Oui, les deux vous donnera exécution différée.
La différence est que
IQueryable<T>
est l'interface qui permet de LINQ-to-SQL (LINQ.-à quelque chose de vraiment. Donc, si vous affiner votre requête sur uneIQueryable<T>
, que la requête sera exécutée dans la base de données, si possible.Pour la
IEnumerable<T>
cas, il sera LINQ-to-objet, ce qui signifie que tous les objets correspondant à la requête d'origine doit être chargé en mémoire à partir de la base de données.Dans le code:
Que le code s'execute SQL pour sélectionner uniquement les clients d'or. Le code suivant, d'autre part, l'exécution de la requête d'origine dans la base de données, puis en filtrant les non-clients d'or dans la mémoire:
C'est tout à fait une grande différence, et de travailler sur
IQueryable<T>
dans de nombreux cas, vous sauver de retour trop grand nombre de lignes de la base de données. Un autre exemple est en train de faire de la pagination: Si vous utilisezet
Ignorer
surIQueryable
, vous aurez seulement le nombre de lignes demandés; le faire que sur uneIEnumerable<T>
sera la cause de toutes vos lignes pour être chargé dans la mémoire.Je voudrais juste exprimer comment facilement votre réponse lire. J'ai lu trois articles sur google avant, j'ai trouvé votre facilement compris, super simple explication de la différence. Merci!!!! +1
Grande explication. Existe-il des situations où IEnumerable serait préférable de IQueryable ?
Oui. Si vous voulez répétée de filtrage sur votre résultat original (plusieurs résultats finaux). De faire ce que sur le IQueryable interface fera plusieurs allers-retours vers la base de données, et de le faire sur IEnumerable va faire un filtrage dans la mémoire, le rendant plus rapide (moins que la quantité de données est ÉNORME)
Une autre raison de préférer
IEnumerable
àIQueryable
est que pas tous LINQ opérations sont prises en charge par tous les fournisseurs LINQ. Donc, tant que vous savez ce que vous faites, vous pouvez utiliserIQueryable
à pousser autant de la requête LINQ fournisseur (LINQ2SQL, EF, NHibernate, MongoDB...). Mais si vous laissez les autres code faire ce qu'il veut avec votreIQueryable
vous finirez par la suite jusqu'en difficulté parce que certains client code utilisé quelque part non prise en charge de l'opération. Je suis d'accord avec la recommandation de ne pas divulguerIQueryable
s "into the wild" par le passé, le dépôt ou l'équivalent de la couche.OriginalL'auteur driis
Haut réponse est bonne, mais il ne mentionne pas l'expression d'arbres qui expliquent "comment" les deux interfaces différentes. Fondamentalement, il existe deux ensembles identiques de extensions LINQ.
Where()
,Sum()
,Count()
,FirstOrDefault()
, etc ont tous deux versions: l'une qui accepte des fonctions et celui qui accepte d'expressions.La
IEnumerable
version signature est:Where(Func<Customer, bool> predicate)
La
IQueryable
version signature est:Where(Expression<Func<Customer, bool>> predicate)
Vous avez probablement été à l'aide de ces deux sans s'en rendre compte parce que les deux sont appelées à l'aide identiques syntaxe:
par exemple
Where(x => x.City == "<City>")
fonctionne sur les deuxIEnumerable
etIQueryable
Lors de l'utilisation de
Where()
sur unIEnumerable
la collecte, le compilateur passe d'une fonction compilée pourWhere()
Lors de l'utilisation de
Where()
sur unIQueryable
la collecte, le compilateur passe une arborescence d'expression àWhere()
. Une arborescence d'expression est comme le reflet du système, mais pour le code. Le compilateur convertit votre code en une structure de données qui décrit ce que votre code dans un format facile à digérer.Pourquoi s'embêter avec cette expression de l'arbre chose? Je veux juste
Where()
pour filtrer mes données.La raison principale est que les deux objectifs EF et Linq2SQL Orm peut convertir des arbres d'expression directement dans SQL où votre code s'exécute beaucoup plus rapidement.
Oh, qui sonne comme un spectacle gratuit boost, dois-je utiliser
AsQueryable()
toute la place dans ce cas?Non,
IQueryable
n'est utile que si les données sous-jacentes fournisseur peut faire quelque chose avec elle. La conversion de quelque chose comme unList
àIQueryable
ne vous sera d'aucun profit.IMO c'est mieux que la accepté de répondre. Cependant, je ne comprends pas une chose: IQueryable ne donne aucun avantage pour les objets ordinaires, OK, mais est-ce pire? Parce que si elle ne donne pas d'avantages, il ne suffit pas de raison de préférer IEnumerable, donc l'idée de l'utilisation de IQueryable tous sur la place reste valable.
Sergey, IQueryable s'étend IEnumerable donc, lorsque vous utilisez IQueryable vous en charger plus de mémoire qu'un IEnumerable instanciation! Voici donc un argument. (stackoverflow.com/questions/12064828/... c++ mais j'ai pensé que je pourrais extrapoler ce)
OriginalL'auteur Jacob
Oui, les deux utilisent l'exécution différée. Nous allons illustrer la différence en utilisant le générateur de profils SQL Server....
Lorsque nous exécutez le code suivant:
Dans SQL Server profiler, nous trouvons une commande égale à:
Il prend environ 90 secondes pour exécuter ce bloc de code sur un Blog de la table de qui a 1 million d'enregistrements.
Donc, tous les enregistrements de la table sont chargés dans la mémoire comme des objets, et ensuite à chaque .Où (), ce sera une autre filtre dans la mémoire à l'égard de ces objets.
Lorsque nous utilisons
IQueryable
au lieu deIEnumerable
dans l'exemple ci-dessus (deuxième ligne):Dans SQL Server profiler, nous trouvons une commande égale à:
Il prend environ quatre secondes pour exécuter ce bloc de code à l'aide de
IQueryable
.IQueryable a une propriété appelée
Expression
qui stocke une arborescence d'expression qui commence à être créé lorsque nous avons utilisé leresult
dans notre exemple (ce qui est appelé l'exécution différée), et à la fin de cette expression sera convertie en une requête SQL à exécuter sur le moteur de base de données.Cela m'apprend lors de la coulée de IEnumerable, le sous-jacent IQueryable perd de sa IQueryable méthode d'extension.
Bonne idée en utilisant le générateur de profils SQL...je n'utilise pas ce mauvais garçon assez!!
OriginalL'auteur Kasper Roma
Les deux vous donnera l'exécution différée, oui.
Que pour ce qui est préférée à une autre, cela dépend de votre source de données sous-jacente est.
Retour d'un
IEnumerable
automatiquement la force de l'exécution pour utiliser LINQ to Objects pour interroger votre collection.Retour d'un
IQueryable
(qui implémenteIEnumerable
, par la voie) fournit la fonctionnalité supplémentaire pour traduire votre requête dans quelque chose qui pourrait mieux fonctionner sur la source sous-jacent (LINQ to SQL, LINQ to XML, etc.).OriginalL'auteur Justin Niessner
En termes généraux, je vous recommande les suivants:
Retour
IQueryable<T>
si vous souhaitez activer le développeur à l'aide de votre méthode pour affiner la requête de retour avant de s'exécuter.Retour
IEnumerable
si vous voulez transporter un ensemble d'Objets à énumérer.Imaginer un
IQueryable
que ce qu'elle est - une "requête" pour les données (que vous pouvez préciser si vous voulez). UnIEnumerable
est un ensemble d'objets (qui a déjà été reçu ou a été créé) sur lesquels vous pouvez énumérer.OriginalL'auteur sebastianmehler
Beaucoup a été dit précédemment, mais d'un retour aux sources, de manière plus technique:
IEnumerable
est une collection d'objets en mémoire que vous pouvez énumérer - en mémoire une séquence qui permet d'itérer (il est facile pour l'intérieur deforeach
boucle, si vous pouvez aller avecIEnumerator
seulement). Ils résident dans la mémoire.IQueryable
est une expression de l'arbre qui sera traduit en quelque chose d'autre à un point avec possibilité d'énumérer sur le résultat final. Je suppose que c'est ce qui confond la plupart des gens.Il est évident qu'ils ont des connotations différentes.
IQueryable
représente une expression de l'arbre (une requête, tout simplement) qui sera traduit en quelque chose d'autre par la requête sous-jacente fournisseur dès que les Api sont appelés, comme LINQ fonctions d'agrégation (Sum, Count, etc.) ou ToList[Tableau, Dictionnaire,...]. EtIQueryable
objets également de mettre en œuvreIEnumerable
,IEnumerable<T>
de sorte que si elles représentent une requête le résultat de cette requête pourrait être réitéré. Cela signifie IQueryable n'ont pas à être les requêtes. Le bon terme, c'est qu'ils sont des arbres d'expression.Maintenant comment ces expressions sont exécutés et qu'ils se tournent vers l'est tous, jusqu'à ce qu'on appelle fournisseurs de requêtes (expression exécuteurs nous pouvons penser à eux).
Dans le Entity Framework monde (qui est mystique de données sous-jacente source prestataire ou fournisseur de requêtes)
IQueryable
expressions sont traduites en natif T-SQL requêtes.Nhibernate
fait des choses similaires avec eux. Vous pouvez écrire votre propre en suivant les concepts assez bien décrite dans LINQ: la Construction d'un IQueryable Fournisseur lien, par exemple, et vous pourriez être personnalisé à l'interrogation de l'API pour votre magasin de produits fournisseur de service.Donc, fondamentalement,
IQueryable
objets se construit tout au long chemin jusqu'à nous libérer explicitement eux et de dire que le système de réécriture dans SQL ou autre et d'envoyer la chaîne d'exécution pour la poursuite du traitement.Comme si de différés exécution, il est un
LINQ
fonctionnalité pour tenir jusqu'à l'expression de l'arbre régime de la mémoire et de l'envoyer dans l'exécution sur demande uniquement, lorsque certaines Api sont appelés à l'encontre de la séquence (le même Comte, ToList, etc.).L'utilisation correcte des deux dépend fortement de l'tâches que vous êtes face à lui, pour le cas spécifique. Pour le modèle de référentiel personnellement, j'ai opt pour revenir
IList
, c'est-àIEnumerable
sur les Listes (indexeurs et autres). C'est donc mes conseils pour utiliserIQueryable
seulement dans les dépôts et IEnumerable n'importe où ailleurs dans le code. Ne pas dire à propos de la testabilité des préoccupations queIQueryable
se décompose et les ruines du la séparation des préoccupations principe. Si vous retournez une expression à partir de l'intérieur de référentiels les consommateurs peuvent jouer avec la couche de persistance comme ils le souhaiteraient.Un peu plus le bordel 🙂 (à partir d'une discussion dans les commentaires))
Aucun d'entre eux sont des objets en mémoire, car ils ne sont pas les types en soi, ils sont les marqueurs d'un type - si vous voulez aller si loin. Mais elle a un sens (et c'est pourquoi même MSDN de mettre de cette façon) à penser IEnumerables que les collections en mémoire alors que IQueryables comme des arbres d'expression. Le point est que le IQueryable interface hérite de l'interface IEnumerable sorte que, si elle représente une requête, les résultats de cette requête peut être énumérés. L'énumération des causes de l'arborescence d'expression associée à un IQueryable objet à être exécuté.
Donc, en fait, on ne peut pas vraiment appeler n'importe quel IEnumerable membre sans avoir l'objet dans la mémoire. Il va y aller si vous le faites, de toute façon, si elle n'est pas vide. IQueryables sont juste des requêtes, pas les données.
donc, en fait, on ne peut pas vraiment appeler n'importe quel IEnumerable membre sans avoir l'objet dans la mémoire. Il va y aller si vous le faites, de toute façon, si elle n'est pas vide. IQueryables sont juste des requêtes, pas les données. Mais je vois vraiment votre point de vue. Je vais ajouter un commentaire sur cet.
aucun d'entre eux sont des objets en mémoire, car ils ne sont pas les types en soi, ils sont les marqueurs d'un type - si vous voulez aller si loin. Mais elle a un sens (et c'est pourquoi même MSDN mettre de cette façon) à penser IEnumerables que les collections en mémoire alors que IQueryables comme des arbres d'expression. Le point est que le IQueryable interface hérite de l'interface IEnumerable sorte que, si elle représente une requête, les résultats de cette requête peut être énumérés. L'énumération des causes de l'arborescence d'expression associée à un IQueryable objet à être exécuté.
OriginalL'auteur Arman McHitarian
En général, vous souhaitez conserver l'original de type statique de la requête jusqu'à ce qu'il questions de.
Pour cette raison, vous pouvez définir la variable 'var' au lieu de
IQueryable<>
ouIEnumerable<>
et vous saurez que vous n'êtes pas changer le type.Si vous commencez avec un
IQueryable<>
, vous souhaitez généralement de le garder comme unIQueryable<>
jusqu'à il y a quelques raison impérieuse de le changer. La raison pour cela est que vous souhaitez donner à la requête du processeur autant d'informations que possible. Par exemple, si vous n'utilisez que 10 résultats (que vous avez appeléTake(10)
) alors vous voulez SQL Server à savoir à ce sujet afin qu'il puisse optimiser ses plans de requête et de vous envoyer seulement les données que vous allez utiliser.Une raison valable pour changer le type de
IQueryable<>
àIEnumerable<>
peut-être que vous appelez une extension de la fonction que la mise en œuvre deIQueryable<>
dans votre objet particulier ne peut pas les gérer ou les poignées de façon inefficace. Dans ce cas, vous pourriez souhaiter pour convertir le type deIEnumerable<>
(par l'affectation à une variable de typeIEnumerable<>
ou à l'aide de laAsEnumerable
méthode d'extension par exemple), de sorte que les fonctions d'extension vous appeler à la fin ceux de laEnumerable
classe au lieu de laQueryable
classe.OriginalL'auteur AJS
Il y a un post de blog avec de brefs exemples de code source sur la façon de détournement de
IEnumerable<T>
peut avoir un impact considérable sur les performances des requêtes LINQ: Entity Framework: IQueryable vs IEnumerable.Si nous creuser plus profondément et de le regarder dans les sources, nous pouvons voir qu'il existe bien évidemment différentes méthodes d'extension sont effectuées pour
IEnumerable<T>
:et
IQueryable<T>
:Le premier retourne énumérable itérateur, et le second crée de la requête par le biais de la requête fournisseur, spécifié dans
IQueryable
source.OriginalL'auteur Olexander Ivanitskyi
ces quelques différences entre les
IQueryable<T>
etIEnumerable<T>
OriginalL'auteur Basheer AL-MOMANI
J'ai récemment rencontré un problème avec
IEnumerable
v.IQueryable
. L'algorithme utilisé d'abord effectué uneIQueryable
requête afin d'obtenir un ensemble de résultats. Ces données ont ensuite été transmis à unforeach
boucle, avec les éléments instanciés comme une Entité Cadre (EF) de la classe. Cet EF classe a ensuite été utilisé dans lefrom
clause de Linq to Entité de requête, à l'origine du résultat àIEnumerable
.Je suis assez nouveau à l'EF et Linq pour les Entités, de sorte qu'il a fallu un certain temps pour comprendre ce que le goulot d'étranglement a été. À l'aide de MiniProfiling, j'ai trouvé la requête, puis converti l'ensemble de ces opérations individuelles à un seul
IQueryable
Linq pour les Entités de la requête. LeIEnumerable
a pris 15 secondes et leIQueryable
a pris de 0,5 secondes à s'exécuter. Il y avait trois tables impliquées et, après cette lecture, je crois que leIEnumerable
requête a été fait en formant un trois de la table de la croix-produit et de filtrer les résultats.Essayez d'utiliser IQueryables comme une règle-de-pouce et le profil de votre travail pour faire vos modifications mesurables.
IQueryable
s sont aussi coincé dans la mémoire une fois que vous avez appelé l'un de ces Api, mais si pas, vous pouvez transmettre l'expression de la pile des calques et jouer avec les filtres jusqu'à ce que l'appel d'API. Bien conçu DAL comme un bon conçus Référentiel permettra de résoudre ce genre de problèmes 😉OriginalL'auteur sscheider
Je tiens à préciser quelques petites choses en raison apparemment contradictoires réponses (surtout entourant IEnumerable).
(1)
IQueryable
étend leIEnumerable
interface. (Vous pouvez envoyer unIQueryable
à quelque chose qui s'attend à desIEnumerable
sans erreur.)(2) les Deux
IQueryable
etIEnumerable
LINQ tentative de chargement différé lors d'une itération sur l'ensemble des résultats. (À noter que la mise en œuvre peut être vu dans l'interface des méthodes d'extension pour chaque type.)En d'autres termes,
IEnumerables
ne sont pas exclusivement "en mémoire".IQueryables
ne sont pas toujours exécutées sur la base de données.IEnumerable
devez charger les choses en mémoire (une fois extraites, éventuellement paresseusement) parce qu'il n'a pas de résumé fournisseur de données.IQueryables
compter sur un résumé fournisseur (comme LINQ-to-SQL), bien que cela pourrait également être le .NET-fournisseur de mémoire.Exemple de cas d'utilisation
(a) Récupérer la liste des records comme
IQueryable
de EF contexte. (Aucun enregistrement n'est en mémoire.)(b) Passer le
IQueryable
à vue, dont le modèle estIEnumerable
. (Valable.IQueryable
s'étendIEnumerable
.)(c) parcourir et d'accéder aux données de l'ensemble des dossiers, de l'enfant, les entités et les propriétés de la vue. (Peut provoquer des exceptions!)
Problèmes Possibles
(1) Le
IEnumerable
tentatives de chargement paresseux et votre contexte de données est expiré. Exception levée, car le fournisseur n'est plus disponible.(2) Cadre de l'Entité entité procurations sont activé (par défaut), et que vous tentez d'accéder à une relative (virtuel) de l'objet à l'expiration d'un contexte de données. Même que (1).
(3) (Multiple Active Result set de MARS). Si vous êtes une itération sur la
IEnumerable
dans unforeach( var record in resultSet )
bloc et, simultanément, de tentative d'accès àrecord.childEntity.childProperty
, vous pouvez vous retrouver avec MARS en raison de paresseux charge à la fois l'ensemble de données et le relationnel de l'entité. Cela va provoquer une exception si elle n'est pas activée dans votre chaîne de connexion.Solution
Exécuter la requête et de stocker les résultats en invoquant
resultList = resultSet.ToList()
Cela semble être la façon la plus simple de s'assurer vos entités sont en mémoire.Dans le cas où vous accédez à des entités liées, vous pouvez toujours besoin d'un contexte de données. Soit ça, ou vous pouvez désactiver l'entité procurations et explicitement
Include
entités liées de votreDbSet
.OriginalL'auteur Alexander Pritchard
La principale différence entre “IEnumerable” et “IQueryable” où la logique de filtre est exécuté. On exécute côté client (dans la mémoire) et de l'autre s'exécute sur la base de données.
Par exemple, on peut considérer un exemple où nous avons 10 000 enregistrements d'un utilisateur dans notre base de données et disons seulement 900 qui sont des utilisateurs actifs, dans ce cas, si nous utilisons la “IEnumerable” alors tout d'abord il charge tous les 10 000 enregistrements dans la mémoire, puis applique le filtre est actif sur ce qui renvoie finalement l'900 utilisateurs actifs.
Tandis que de l'autre main sur le même cas, si nous utilisons la “IQueryable” il va directement appliquer le filtre est actif sur la base de données directement à partir de là sera de retour le 900 utilisateurs actifs.
Référence Lien
est plus privilégiées en termes d'être optimisé et un poids léger.
OriginalL'auteur Tabish Usman
Nous pouvons utiliser les deux de la même manière, et ils ne sont différents dans la performance.
IQueryable s'exécute uniquement sur la base de données d'une manière efficace. Cela signifie qu'il crée toute une requête select et obtient uniquement les enregistrements liés.
Par exemple, nous voulons prendre le top 10 les clients dont le nom commence par ‘Nimal’. Dans ce cas, la requête select sera généré en tant que
select top 10 * from Customer where name like ‘Nimal%’
.Mais si nous avons utilisé IEnumerable, la requête serait comme
select * from Customer where name like ‘Nimal%’
et les top dix seront filtrés à la C# codage de niveau (il obtient tous les dossiers des clients de la base de données et les transmet en C#).OriginalL'auteur user3710357
En plus des 2 premières bonnes réponses (par driis & par Jacob) :
L'objet IEnumerable représente un ensemble de données dans la mémoire et peut se déplacer sur ces données uniquement vers l'avant. La requête représentée par l'objet IEnumerable est exécuté immédiatement et complètement, de sorte que l'application reçoit les données rapidement.
Lorsque la requête est exécutée, IEnumerable charge toutes les données, et si nous avons besoin de filtre, le filtrage se fait sur le côté client.
Le IQueryable objet fournit un accès à distance à la base de données et vous permet de naviguer à travers les données dans un ordre direct du début à la fin, ou dans l'ordre inverse. Dans le processus de création d'une requête, l'objet retourné est IQueryable, la requête est optimisée. En conséquence, moins la mémoire est consommée lors de son exécution, à moins de bande passante réseau, mais en même temps, il peut être traité un peu plus lentement qu'une requête qui retourne un objet IEnumerable.
Que choisir?
Si vous avez besoin de l'ensemble de données retourné, alors il est préférable d'utiliser IEnumerable, qui fournit le maximum de vitesse.
Si vous N'avez PAS besoin de l'ensemble des données renvoyées, mais seulement une partie des données filtrées, puis il est préférable d'utiliser IQueryable.
OriginalL'auteur Gleb B
IEnumrable va stocker les données dans une mémoire
Mais dans le cas de Iqueruable ce n'est pas stocker dans une mémoire
Pour plus de détails, vous vérifiez avec le générateur de profils sql
Temps de poing que vous a frappé
requête avec IQueryable
Et de voir ce que la requête execute
Puis essayez de IEnumrable
OriginalL'auteur Arpit Srivastava