Question

Étant donné la requête LINQ to SQL suivante :

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

L'instruction SQL interprétée est :

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

Supposons que je veuille effectuer une action dans la sélection qui ne peut pas être convertie en SQL.Je crois comprendre que la manière conventionnelle d'y parvenir est de faire AsEnumerable() le convertissant ainsi en un objet exploitable.

Compte tenu de ce code mis à jour :

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

Et SQL mis à jour :

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

Notez l'absence de clause Where dans l'instruction SQL exécutée.

Cela signifie-t-il que l'intégralité de la table « Importations » est mise en cache en mémoire ?Cela ralentirait-il les performances si la table contenait une grande quantité d'enregistrements ?

Aidez-moi à comprendre ce qui se passe réellement dans les coulisses.

Était-ce utile?

La solution

La raison pour CommeEnumerable est de

Asenuableable (tsource) (ienumerable (tsource)) peut être utilisé pour choisir entre les implémentations de requête lorsqu'une séquence implémente ienumerable (t) mais a également un ensemble différent de méthodes de requête publique disponibles

Alors, quand tu appelais le Where méthode avant, vous appeliez un autre Where méthode de la IEnumerable.Where.Que Where L'instruction était pour LINQ de convertir en SQL, le nouveau Where est le IEnumerable celui qui prend un IEnumerable, l'énumère et génère les éléments correspondants.Ce qui explique pourquoi vous voyez les différents SQL générés.Le tableau sera extrait intégralement de la base de données avant le Where l'extension sera appliquée dans votre deuxième version du code.Cela pourrait créer un sérieux goulot d'étranglement, car la table entière doit être en mémoire, ou pire, la table entière devrait voyager entre les serveurs.Autoriser le serveur SQL à exécuter le Where et faire ce qu'il fait de mieux.

Autres conseils

Au point où l'énumération est effectuée, la base de données sera alors interrogée et l'ensemble des résultats sera récupéré.

Une solution partielle peut être la solution.Considérer

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

Disons également que NonDatabaseConvertableCriterion requiert le champ C du résultat.Étant donné que NonDatabaseConvertableCriterion fait ce que son nom suggère, cela doit être effectué sous forme d'énumération.Cependant, considérez :

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é, interrogé ou utilisé d'une autre manière, autant de travail que possible sera transmis à la base de données, qui en renverra suffisamment pour continuer le travail.En supposant qu’il soit effectivement impossible de réécrire pour que tout le travail puisse être envoyé vers la base de données, cela peut être un compromis approprié.

Il existe trois implémentations de AsEnumerable.

DataTableExtensions.AsEnumerable

Prolonge un DataTable pour lui donner un IEnumerable interface afin que vous puissiez utiliser Linq contre le DataTable.

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

Le AsEnumerable<TSource>(IEnumerable<TSource>) La méthode n'a pas d'autre effet que de modifier le type de source de compilation à partir d'un type qui implémente IEnumerable<T> à 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 s'implémente IEnumerable<T> mais dispose également d'un ensemble différent de méthodes de requête publique.Par exemple, étant donné une classe générique Table qui met en œuvre IEnumerable<T> et possède ses propres méthodes telles que Where, Select, et SelectMany, un appel à Where invoquerait le public Where méthode de Table.UN Table le type qui représente une table de base de données peut avoir un Where Méthode qui prend l'argument du prédicat comme une arborescence d'expression et convertit l'arborescence en SQL pour l'exécution à distance.Si une exécution à distance n'est pas souhaitée, par exemple parce que le prédicat invoque une méthode locale, la AsEnumerable<TSource> La méthode peut être utilisée pour masquer les méthodes personnalisées et rendre les opérateurs de requête standard disponibles.

Autrement dit.

Si j'ai un

IQueryable<X> sequence = ...;

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

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

cette requête sera composée et exécutée sur le serveur.Cela échouera au moment de l'exécution car EntityFramework ne sait pas comment convertir SomeUnusualPredicate en SQL.

Si je veux que cela exécute l'instruction avec Linq to Objects à la place, je le fais,

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

maintenant le serveur renverra toutes les données et le Enumerable.Where from Linq to Objects sera utilisé à la place de l’implémentation du fournisseur de requêtes.

Peu importe qu'Entity Framework ne sache pas comment interpréter SomeUnusualPredicate, ma fonction sera utilisée directement.(Cependant, cela peut s'avérer une approche inefficace puisque toutes les lignes seront renvoyées par le serveur.)

Je crois que AsEnumerable indique simplement au compilateur quelles méthodes d'extension utiliser (dans ce cas, celles définies pour IEnumerable au lieu de celles pour IQueryable).L'exécution de la requête est toujours différée jusqu'à ce que vous appeliez ToArray ou que vous l'énumétiez.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top