54 votes

La compréhension .AsEnumerable() dans LINQ to SQL

Compte tenu de la suite de LINQ to SQL de la requête:

var test = from i in Imports
           where i.IsActive
           select i;

L'interprete de l'instruction SQL:

SELECT [t0].[id] AS [Id] .... FROM [Imports] AS [t0] WHERE [t0].[isActive] = 1

Dire que je voulais réaliser une action dans la sélection qui ne peuvent être converties en SQL. Sa ma compréhension que la façon traditionnelle pour accomplir cela est de faire AsEnumerable() donc de le convertir à une pratique de l'objet.

Compte tenu de cette mise à jour de code:

var test = from i in Imports.AsEnumerable()
           where i.IsActive
           select new 
           { 
               // Make some method call 
           };

Et mise à jour de SQL:

SELECT [t0].[id] AS [Id] ... FROM [Imports] AS [t0] 

Constater l'absence d'une clause where dans l'instruction SQL exécutée.

Est-ce à dire l'ensemble de la "Importations" de la table est mis en cache dans la mémoire? Serait-ce le ralentissement des performances à tous si la table contient une grande quantité de documents?

Aide-moi à comprendre ce qui se passe réellement derrière les scènes.

43voto

Yuriy Faktorovich Points 33347

La raison pour AsEnumerable est à

AsEnumerable(TSource)(IEnumerable(TSource)) peut être utilisé pour choisir entre la requête les implémentations lorsqu'une séquence implémentant IEnumerable(T) mais aussi a un ensemble différent de requête publique les méthodes disponibles

Ainsi, lorsque vous étiez en appelant la méthode avant, vous étiez en appelant un autre Où la méthode de l'interface IEnumerable.Où. Que, Lorsque la déclaration a été pour LINQ to convertir SQL, le nouveau Où est l'interface IEnumerable celui qui prend un IEnumerable, énumère et donne les éléments correspondants. Ce qui explique pourquoi vous voyez les différents SQL généré. La table sera pris en totalité à partir de la base de données avant de l'endroit Où sera appliquée dans votre deuxième version du code. Cela pourrait créer un sérieux goulot de bouteille, car l'ensemble de la table doit être en mémoire, ou pire la totalité de la table devrait voyager entre les serveurs. Permettre de SQL server pour exécuter le Où et faire ce qu'il fait de mieux.

9voto

Jon Hanna Points 40291

Au point où l'énumération est énumérée par le biais de la base de données sera ensuite interrogé, et l'ensemble du jeu de résultats récupérés.

Une partie-et une partie de la solution peut être la voie. Envisager

var res = (
    from result in SomeSource
    where DatabaseConvertableCriterion(result)
    && NonDatabaseConvertableCriterion(result)
    select new {result.A, result.B}
);

Disons aussi que NonDatabaseConvertableCriterion nécessite champ C de résultat. Parce que NonDatabaseConvertableCriterion fait ce que son nom l'indique, cette opération doit être effectuée comme une énumération. Cependant, pensez à:

var partWay =
(
    from result in SomeSource
    where DatabaseConvertableCriterion(result)
    select new {result.A, result.B, result.C}
);
var res =
(
    from result in partWay.AsEnumerable()
    where NonDatabaseConvertableCriterion select new {result.A, result.B}
);

Dans ce cas, lorsque res est énuméré, d'interrogation ou utilisée d'une autre manière, autant de travail que possible sera transmis à la base de données, qui sera de retour assez pour continuer le travail. En supposant qu'il est vraiment impossible de réécrire, de sorte que tout le travail peut être envoyé à la base de données, cela peut être un bon compromis.

6voto

Jodrell Points 14205

Il y a trois implémentations de AsEnumerable.

DataTableExtensions.AsEnumerable

S'étend un DataTable une IEnumerable interface de sorte que vous pouvez utiliser Linq contre l' DataTable.

Enumerable.AsEnumerable<TSource> et ParallelEnumerable.AsEnumerable<TSource>

L' AsEnumerable<TSource>(IEnumerable<TSource>) méthode n'a aucun effet plutôt que de changer le type de compilation de la source à partir d'un type de implémente IEnumerable<T> de IEnumerable<T> lui-même.

AsEnumerable<TSource>(IEnumerable<TSource>) peut être utilisé pour choisir entre les implémentations de requête lorsqu'une séquence met en œuvre IEnumerable<T> , mais a également une autre série de méthodes de requête disponible. Par exemple, étant donné une classe générique Table qui implémente IEnumerable<T> et a ses propres méthodes telles que l' Where, Select, et SelectMany, un appel à l' Where invoquent le public Where méthode de Table. Un Table type qui représente une table de base de données pourrait avoir un Where méthode qui prend le prédicat argument comme une expression de l'arbre et convertit l'arbre à SQL pour l'exécution à distance. Si l'exécution à distance n'est pas souhaitée, par exemple parce que le prédicat invoque un local de la méthode, l' AsEnumerable<TSource> méthode peut être utilisée pour masquer la méthodes personnalisées et de prendre plutôt les opérateurs de requête standard disponible.

En d'autres termes.

Si j'ai un

IQuerable<X> sequence = ...;

à partir d'un LinqProvider, comme Entity Framework, et je le fais,

sequence.Where(x => SomeUnusualPredicate(x));

cette requête sera composé et exécuté sur le serveur. On va à l'échec à l'exécution parce que le EntityFramework ne savez pas comment convertir SomeUnusualPredicate en SQL.

Si je veux que pour exécuter l'instruction avec Linq to Objects au lieu de cela, je le fais,

sequence.AsEnumerable().Where(x => SomeUnusualPredicate(x));

maintenant que le serveur va renvoyer toutes les données et l' Enumerable.Where de Linq to Objects sera utilisé à la place de la Requête du Fournisseur de la mise en œuvre.

Il ne sera pas question que Entity Framework ne sais pas comment interpréter SomeUnusualPredicate, ma fonction sera utilisée directement. (Cependant, cela peut être une mauvaise approche, car toutes les lignes seront retournées par le serveur.)

2voto

Razvi Points 1059

Je crois que le AsEnumerable indique au compilateur les méthodes d'extension à utiliser (dans ce cas, celles définies pour IEnumerable à la place de ceux pour IQueryable). L'exécution de la requête est toujours différée jusqu'à ce que vous appelez ToArray ou de les énumérer sur elle.

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