Je connais certaines différences de LINQ to Entities et LINQ to Objects que le premier implémente IQueryable
et le second implémente IEnumerable
et la portée de ma question est dans EF 5.
Ma question est quelle (s) différence (s) technique (s) de ces 3 méthodes? Je vois que dans de nombreuses situations, tous fonctionnent. Je vois aussi utiliser des combinaisons d'entre eux comme .ToList().AsQueryable()
.
Que signifient exactement ces méthodes?
Y a-t-il un problème de performance ou quelque chose qui conduirait à l'utilisation de l'un sur l'autre?
Pourquoi utiliserait-on, par exemple,
.ToList().AsQueryable()
au lieu de.AsQueryable()
?
Réponses:
Il y a beaucoup à dire à ce sujet. Permettez - moi de mettre l' accent sur
AsEnumerable
etAsQueryable
et mentionner leToList()
long du chemin.Que font ces méthodes?
AsEnumerable
etAsQueryable
cast ou convertir enIEnumerable
ouIQueryable
, respectivement. Je dis lancer ou convertir avec une raison:Lorsque l'objet source implémente déjà l'interface cible, l'objet source lui-même est renvoyé mais converti en interface cible. En d'autres termes: le type n'est pas modifié, mais le type à la compilation l'est.
Lorsque l'objet source n'implémente pas l'interface cible, l'objet source est converti en un objet qui implémente l'interface cible. Ainsi, le type et le type au moment de la compilation sont modifiés.
Laissez-moi vous montrer cela avec quelques exemples. J'ai cette petite méthode qui rapporte le type de compilation et le type réel d'un objet ( avec la permission de Jon Skeet ):
Essayons un linq-to-sql arbitraire
Table<T>
, qui implémenteIQueryable
:Le résultat:
Vous voyez que la classe de table elle-même est toujours renvoyée, mais sa représentation change.
Maintenant un objet qui implémente
IEnumerable
, pasIQueryable
:Les resultats:
Le voilà.
AsQueryable()
a converti le tableau en unEnumerableQuery
, qui "représente unIEnumerable<T>
collection en tant queIQueryable<T>
source de données». (MSDN).Quel en est l'usage?
AsEnumerable
est fréquemment utilisé pour passer de touteIQueryable
implémentation à LINQ vers des objets (L2O), principalement parce que le premier ne prend pas en charge les fonctions de L2O. Pour plus de détails, voir Quel est l'effet de AsEnumerable () sur une entité LINQ? .Par exemple, dans une requête Entity Framework, nous ne pouvons utiliser qu'un nombre limité de méthodes. Donc, si, par exemple, nous devons utiliser l'une de nos propres méthodes dans une requête, nous écrirons généralement quelque chose comme
ToList
- qui convertit unIEnumerable<T>
en aList<T>
- est également souvent utilisé à cette fin. L'avantage d'utiliserAsEnumerable
vs.ToList
est qu'ilAsEnumerable
n'exécute pas la requête.AsEnumerable
préserve l'exécution différée et ne construit pas une liste intermédiaire souvent inutile.D'autre part, lorsque l'exécution forcée d'une requête LINQ est souhaitée,
ToList
peut être un moyen de le faire.AsQueryable
peut être utilisé pour qu'une collection énumérable accepte des expressions dans des instructions LINQ. Voir ici pour plus de détails: Ai-je vraiment besoin d'utiliser AsQueryable () sur la collecte? .Remarque sur la toxicomanie!
AsEnumerable
fonctionne comme une drogue. C'est une solution rapide, mais à un coût et ne résout pas le problème sous-jacent.Dans de nombreuses réponses Stack Overflow, je vois des personnes postuler
AsEnumerable
pour résoudre à peu près n'importe quel problème avec des méthodes non prises en charge dans les expressions LINQ. Mais le prix n'est pas toujours clair. Par exemple, si vous faites ceci:... tout est proprement traduit en une instruction SQL qui filtre (
Where
) et projette (Select
). Autrement dit, la longueur et la largeur, respectivement, du jeu de résultats SQL sont réduites.Supposons maintenant que les utilisateurs ne souhaitent voir que la partie date de
CreateDate
. Dans Entity Framework, vous découvrirez rapidement que ...... n'est pas pris en charge (au moment de la rédaction). Ah, heureusement, il y a le
AsEnumerable
correctif:Bien sûr, il fonctionne, probablement. Mais il tire la table entière en mémoire et applique ensuite le filtre et les projections. Eh bien, la plupart des gens sont assez intelligents pour faire le
Where
premier:Cependant, toutes les colonnes sont récupérées en premier et la projection est effectuée en mémoire.
La vraie solution est:
(Mais cela nécessite juste un peu plus de connaissances ...)
Que ne font PAS ces méthodes?
Restaurer les capacités IQueryable
Maintenant une mise en garde importante. Quand tu fais
vous vous retrouverez avec l'objet source représenté par
IQueryable
. (Parce que les deux méthodes ne font que lancer et ne pas convertir)Mais quand tu fais
quel sera le résultat?
Le
Select
produit unWhereSelectEnumerableIterator
. Il s'agit d'une classe .Net interne qui implémenteIEnumerable
, nonIQueryable
. Ainsi, une conversion vers un autre type a eu lieu et la suiteAsQueryable
ne peut plus jamais retourner la source d'origine.L'implication de cela est que l'utilisation
AsQueryable
n'est pas un moyen d'injecter par magie un fournisseur de requêtes avec ses fonctionnalités spécifiques dans un énumérable. Supposez que vous faitesLa condition where ne sera jamais traduite en SQL.
AsEnumerable()
suivi d'instructions LINQ coupe définitivement la connexion avec le fournisseur de requêtes de structure d'entité.Je montre délibérément cet exemple parce que j'ai vu des questions ici où les gens, par exemple, essaient d'injecter des
Include
capacités dans une collection en appelantAsQueryable
. Il se compile et s'exécute, mais il ne fait rien car l'objet sous-jacent n'a pas deInclude
implémentation.Exécuter
Les deux
AsQueryable
etAsEnumerable
n'exécutent pas (ou n'énumèrent ) pas l'objet source. Ils changent uniquement de type ou de représentation. Les deux interfaces impliquées,IQueryable
etIEnumerable
, ne sont rien d'autre qu'une "énumération en attente de se produire". Ils ne sont pas exécutés avant d'être obligés de le faire, par exemple, comme mentionné ci-dessus, en appelantToList()
.Cela signifie que l'exécution d'un
IEnumerable
obtenu en appelantAsEnumerable
unIQueryable
objet exécutera le sous-jacentIQueryable
. Une exécution ultérieure duIEnumerable
exécutera à nouveau leIQueryable
. Ce qui peut être très coûteux.Implémentations spécifiques
Jusqu'à présent, il ne s'agissait que des méthodes d'extension
Queryable.AsQueryable
etEnumerable.AsEnumerable
. Mais bien sûr, n'importe qui peut écrire des méthodes d'instance ou des méthodes d'extension avec les mêmes noms (et fonctions).En fait, un exemple courant de
AsEnumerable
méthode d'extension spécifique estDataTableExtensions.AsEnumerable
.DataTable
n'implémente pasIQueryable
ouIEnumerable
, donc les méthodes d'extension habituelles ne s'appliquent pas.la source
AsQueryable()
est souvent basée sur une idée fausse. Mais je vais laisser mijoter dans le dos de ma tête pendant un moment et voir si je peux ajouter un peu plus de couverture sur cette question.Lister()
AsEnumerable ()
Func<TSource, bool>
AsQueryable ()
Expression<Func<TSource, bool>>
AsQueryable()
fonctionne donc généralement beaucoup plus rapidement queAsEnumerable()
lorsqu'il génère T-SQL au début, qui inclut toutes vos conditions where dans votre Linq.la source
ToList () sera tout en mémoire et vous travaillerez dessus. donc, ToList (). où (appliquer un filtre) est exécuté localement. AsQueryable () exécutera tout à distance c'est-à-dire qu'un filtre sur celui-ci est envoyé à la base de données pour application. Queryable ne fait rien tant que vous ne l'exécutez pas. ToList, cependant, s'exécute immédiatement.
Regardez également cette réponse Pourquoi utiliser AsQueryable () au lieu de List ()? .
EDIT: De plus, dans votre cas, une fois que vous faites ToList (), toutes les opérations suivantes sont locales, y compris AsQueryable (). Vous ne pouvez pas passer à distant une fois que vous avez commencé à exécuter localement. J'espère que cela rend les choses un peu plus claires.
la source
Rencontré une mauvaise performance sur le code ci-dessous.
Fixé avec
Pour un IQueryable, restez dans IQueryable lorsque cela est possible, essayez de ne pas être utilisé comme IEnumerable.
Mettre à jour . Il peut être encore simplifié en une seule expression, merci Gert Arnold .
la source