Renvoyer IEnumerable <T> par rapport à IQueryable <T>

1085

Quelle est la différence entre le retour IQueryable<T>et le IEnumerable<T>moment où l'un devrait être préféré à l'autre?

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;
stackoverflowuser
la source

Réponses:

1778

Oui, les deux vous donneront une exécution différée .

La différence est que IQueryable<T>c'est l'interface qui permet à LINQ-to-SQL (LINQ.-to-everything vraiment) de fonctionner. Donc, si vous affinez davantage votre requête sur un IQueryable<T>, cette requête sera exécutée dans la base de données, si possible.

Pour le IEnumerable<T>cas, il s'agira de LINQ-to-object, ce qui signifie que tous les objets correspondant à la requête d'origine devront être chargés en mémoire à partir de la base de données.

Dans du code:

IQueryable<Customer> custs = ...;
// Later on...
var goldCustomers = custs.Where(c => c.IsGold);

Ce code exécutera SQL pour sélectionner uniquement les clients Gold. Le code suivant, d'autre part, exécutera la requête d'origine dans la base de données, puis filtrera les clients non or dans la mémoire:

IEnumerable<Customer> custs = ...;
// Later on...
var goldCustomers = custs.Where(c => c.IsGold);

C'est une différence assez importante, et travailler sur IQueryable<T>peut dans de nombreux cas vous éviter de renvoyer trop de lignes de la base de données. Un autre bon exemple est la pagination: si vous utilisez Takeet Skipallumez IQueryable, vous n'obtiendrez que le nombre de lignes demandé; faire cela sur un IEnumerable<T>entraînera le chargement de toutes vos lignes en mémoire.

driis
la source
32
Grande explication. Y a-t-il des situations où IEnumerable serait préférable à IQueryable?
fjxx
8
Nous pouvons donc dire que si nous utilisons IQueryable pour interroger un objet mémoire, alors il n'y aura aucune différence entre IEnumerable et IQueryable?
Tarik
11
AVERTISSEMENT: bien qu'IQueryable puisse être une solution tentante en raison de l'optimisation indiquée, elle ne doit pas être autorisée au-delà du référentiel ou de la couche de service. Il s'agit de protéger votre base de données contre la surcharge causée par «l'empilement des expressions LINQ».
Yorro
48
@fjxx Oui. Si vous souhaitez un filtrage répété sur votre résultat d'origine (plusieurs résultats finaux). Faire cela sur l'interface IQueryable fera plusieurs allers-retours à la base de données, où comme le faire sur IEnumerable fera le filtrage dans la mémoire, le rendant plus rapide (sauf si la quantité de données est ÉNORME)
Per Hornshøj-Schierbeck
34
Une autre raison de préférer IEnumerableà IQueryableest que toutes les opérations de LINQ sont pris en charge par tous les fournisseurs de LINQ. Donc, tant que vous savez ce que vous faites, vous pouvez utiliser IQueryablepour envoyer autant de requêtes au fournisseur LINQ (LINQ2SQL, EF, NHibernate, MongoDB, etc.). Mais si vous laissez un autre code faire ce qu'il veut avec votre, IQueryablevous finirez par avoir des problèmes parce que du code client quelque part a utilisé une opération non prise en charge. Je suis d'accord avec la recommandation de ne pas libérer IQueryables "dans la nature" après le référentiel ou la couche équivalente.
Avish
302

La première réponse est bonne mais elle ne mentionne pas d'arbres d'expression qui expliquent "en quoi" les deux interfaces diffèrent. Fondamentalement, il existe deux ensembles identiques d'extensions LINQ. Where(), Sum(), Count(), FirstOrDefault(), Etc ont tous deux versions: l' une qui accepte les fonctions et qui accepte les expressions.

  • La IEnumerablesignature de la version est:Where(Func<Customer, bool> predicate)

  • La IQueryablesignature de la version est:Where(Expression<Func<Customer, bool>> predicate)

Vous avez probablement utilisé les deux sans vous en rendre compte, car les deux sont appelés en utilisant une syntaxe identique:

par exemple Where(x => x.City == "<City>")fonctionne à la fois sur IEnumerableetIQueryable

  • Lors de l'utilisation Where()sur une IEnumerablecollection, le compilateur transmet une fonction compilée àWhere()

  • Lors de l'utilisation Where()sur unIQueryable collection, le compilateur transmet une arborescence d'expression à Where(). Un arbre d'expression est comme le système de réflexion mais pour le code. Le compilateur convertit votre code en une structure de données qui décrit ce que fait votre code dans un format facilement digestible.

Pourquoi s'embêter avec ce truc d'arbre d'expression? je veux justeWhere() filtrer mes données. La raison principale est que les ORM EF et Linq2SQL peuvent convertir les arborescences d'expression directement en SQL où votre code s'exécutera beaucoup plus rapidement.

Oh, cela ressemble à une amélioration des performances gratuite, dois-je utiliser AsQueryable()partout dans ce cas? Non, IQueryablen'est utile que si le fournisseur de données sous-jacent peut en faire quelque chose. Conversion de quelque chose comme un habitué Listde IQueryablevous ne donnera aucun avantage.

Jacob
la source
9
OMI, c'est mieux que la réponse acceptée. Cependant, je n'obtiens pas une chose: IQueryable ne donne aucun avantage pour les objets normaux, OK, mais est-ce pire de toute façon? Parce que si cela ne donne aucun avantage, ce n'est pas une raison suffisante pour préférer IEnumerable, donc l'idée d'utiliser IQueryable partout reste valable.
Sergei Tachenov
1
Sergey, IQueryable étend IEnumerable, donc lorsque vous utilisez IQueryable, vous chargez plus en mémoire qu'une instanciation IEnumerable! Voici donc un argument. ( stackoverflow.com/questions/12064828/… c ++ bien que je pensais que je pouvais extrapoler cela)
Viking
D'accord avec Sergei sur le fait que c'est la meilleure réponse (bien que la réponse acceptée soit très bien). Je rajouterais que dans mon expérience, IQueryablene pas les fonctions parse ainsi que le IEnumerablefait: par exemple, si vous voulez savoir quels sont les éléments d'un DBSet<BookEntity>ne sont pas en List<BookObject>, dbSetObject.Where(e => !listObject.Any(o => o.bookEntitySource == e))lève une exception: Expression of type 'BookEntity' cannot be used for parameter of type 'BookObject' of method 'Boolean Contains[BookObject] (IEnumerable[BookObject], BookObject)'. J'ai dû ajouter .ToList()après dbSetObject.
Jean-David Lanz
80

Oui, les deux utilisent une exécution différée. Illustrons la différence en utilisant le profileur SQL Server ....

Lorsque nous exécutons le code suivant:

MarketDevEntities db = new MarketDevEntities();

IEnumerable<WebLog> first = db.WebLogs;
var second = first.Where(c => c.DurationSeconds > 10);
var third = second.Where(c => c.WebLogID > 100);
var result = third.Where(c => c.EmailAddress.Length > 11);

Console.Write(result.First().UserName);

Dans le profileur SQL Server, nous trouvons une commande égale à:

"SELECT * FROM [dbo].[WebLog]"

Il faut environ 90 secondes pour exécuter ce bloc de code sur une table WebLog contenant 1 million d'enregistrements.

Ainsi, tous les enregistrements de table sont chargés en mémoire en tant qu'objets, puis avec chaque .Where (), ce sera un autre filtre en mémoire par rapport à ces objets.

Lorsque nous utilisons IQueryableau lieu deIEnumerable dans l'exemple ci-dessus (deuxième ligne):

Dans le profileur SQL Server, nous trouvons une commande égale à:

"SELECT TOP 1 * FROM [dbo].[WebLog] WHERE [DurationSeconds] > 10 AND [WebLogID] > 100 AND LEN([EmailAddress]) > 11"

Il faut environ quatre secondes pour exécuter ce bloc de code en utilisant IQueryable .

IQueryable a une propriété appelée Expressionqui stocke une expression d'arbre qui commence à être créée lorsque nous avons utilisé le resultdans notre exemple (qui est appelé exécution différée), et à la fin, cette expression sera convertie en une requête SQL à exécuter sur le moteur de base de données.

Kasper Roma
la source
5
Cela m'apprend lors de la conversion vers IEnumerable, le sous-jacent IQueryable perd sa méthode d'extension IQueryable.
Yiping
56

Les deux vous donneront une exécution différée, oui.

Quant à ce qui est préféré à l'autre, cela dépend de votre source de données sous-jacente.

Renvoyer un IEnumerableforcera automatiquement le runtime à utiliser LINQ to Objects pour interroger votre collection.

Le retour d'un IQueryable(qui implémente IEnumerable, soit dit en passant) fournit la fonctionnalité supplémentaire pour traduire votre requête en quelque chose qui pourrait mieux fonctionner sur la source sous-jacente (LINQ to SQL, LINQ to XML, etc.).

Justin Niessner
la source
30

En termes généraux, je recommanderais ce qui suit:

  • Renvoyez IQueryable<T>si vous souhaitez activer le développeur à l'aide de votre méthode pour affiner la requête que vous renvoyez avant de l'exécuter.

  • Retournez IEnumerablesi vous voulez transporter un ensemble d'objets à énumérer.

Imaginez un IQueryabletel que c'est - une "requête" pour les données (que vous pouvez affiner si vous le souhaitez). An IEnumerableest un ensemble d'objets (qui a déjà été reçu ou a été créé) sur lequel vous pouvez énumérer.

sebastianmehler
la source
2
"Peut énumérer," pas "peut IEnumerable."
Casey
28

Beaucoup a été dit précédemment, mais revenons aux racines, de manière plus technique:

  1. IEnumerable est une collection d'objets en mémoire que vous pouvez énumérer - une séquence en mémoire qui permet de parcourir (facilite la foreachboucle intra , bien que vous ne puissiez y aller qu'avec IEnumerator). Ils résident dans la mémoire telle quelle.
  2. IQueryable est un arbre d'expression qui sera traduit en quelque chose d'autre à un moment donné avec la possibilité d'énumérer le résultat final . Je suppose que c'est ce qui déroute la plupart des gens.

Ils ont évidemment des connotations différentes.

IQueryablereprésente un arbre d'expression (une requête, simplement) qui sera traduit en quelque chose d'autre par le fournisseur de requête sous-jacent dès que les API de publication sont appelées, comme les fonctions d'agrégation LINQ (Sum, Count, etc.) ou ToList [Array, Dictionary ,. ..]. Et les IQueryableobjets implémentent également IEnumerable, de IEnumerable<T>sorte que s'ils représentent une requête, le résultat de cette requête puisse être itéré. Cela signifie que IQueryable ne doit pas être uniquement des requêtes. Le bon terme est qu'ils sont des arbres d'expression .

Maintenant, la façon dont ces expressions sont exécutées et vers quoi elles se tournent appartient aux soi-disant fournisseurs de requêtes (exécuteurs d'expressions auxquels nous pouvons penser).

Dans le monde Entity Framework (qui est ce fournisseur de source de données sous-jacent mystique, ou le fournisseur de requêtes), les IQueryableexpressions sont traduites en requêtes T-SQL natives . Nhibernatefait des choses similaires avec eux. Vous pouvez écrire le vôtre en suivant les concepts assez bien décrits dans LINQ: création d'un lien de fournisseur IQueryable , par exemple, et vous souhaiterez peut-être avoir une API de requête personnalisée pour votre service de fournisseur de magasin de produits.

Donc, fondamentalement, les IQueryableobjets sont construits tout le temps jusqu'à ce que nous les libérions explicitement et disions au système de les réécrire dans SQL ou autre et d'envoyer la chaîne d'exécution pour un traitement ultérieur.

Comme pour une exécution différée, il est possible LINQde conserver le schéma d'arborescence d'expressions dans la mémoire et de l'envoyer dans l'exécution uniquement à la demande, chaque fois que certaines API sont appelées par rapport à la séquence (les mêmes Count, ToList, etc.).

La bonne utilisation des deux dépend fortement des tâches auxquelles vous êtes confronté dans le cas spécifique. Pour le modèle de référentiel bien connu, j'opte personnellement pour le retour IList, c'est-à-dire IEnumerablesur les listes (indexeurs et similaires). Il est donc mon conseil de n'utiliser IQueryableque dans les référentiels et IEnumerable n'importe où ailleurs dans le code. Ne pas parler des problèmes de testabilité qui IQueryabledécomposent et ruinent le principe de séparation des préoccupations . Si vous renvoyez une expression à partir de référentiels, les consommateurs peuvent jouer avec la couche de persistance comme ils le souhaitent.

Un petit ajout au gâchis :) (d'après une discussion dans les commentaires)) Aucun d'entre eux n'est un objet en mémoire car ce ne sont pas de vrais types en soi, ce sont des marqueurs d'un type - si vous voulez aller aussi loin. Mais il est logique (et c'est pourquoi même MSDN le dit ainsi) de considérer IEnumerables comme des collections en mémoire tandis que IQueryables comme des arbres d'expression. Le fait est que l'interface IQueryable hérite de l'interface IEnumerable de sorte que si elle représente une requête, les résultats de cette requête peuvent être énumérés. L'énumération entraîne l'exécution de l'arborescence d'expression associée à un objet IQueryable. Donc, en fait, vous ne pouvez pas vraiment appeler un membre IEnumerable sans avoir l'objet en mémoire. Il y entrera si vous le faites, de toute façon, s'il n'est pas vide. Les IQueryables ne sont que des requêtes, pas les données.

Arman McHitarian
la source
3
Le commentaire selon lequel IEnumerables sont toujours en mémoire n'est pas nécessairement vrai. L'interface IQueryable implémente l'interface IEnumerable. Pour cette raison, vous pouvez passer un IQueryable brut qui représente une requête LINQ-to-SQL directement dans une vue qui attend un IEnumerable! Vous pourriez être surpris de constater que votre contexte de données a expiré ou que vous finissez par rencontrer des problèmes avec MARS (plusieurs jeux de résultats actifs).
donc, en fait, vous ne pouvez pas vraiment appeler un membre IEnumerable sans avoir l'objet en mémoire. Il y entrera si vous le faites, de toute façon, s'il n'est pas vide. Les IQueryables ne sont que des requêtes, pas les données. Mais je vois vraiment votre point. Je vais ajouter un commentaire à ce sujet.
Arman McHitarian
@AlexanderPritchard aucun d'entre eux n'est un objet en mémoire car ce ne sont pas de vrais types en soi, ce sont des marqueurs d'un type - si vous voulez aller aussi loin. Mais il est logique (et c'est pourquoi même MSDN le dit ainsi) de considérer IEnumerables comme des collections en mémoire tandis que IQueryables comme des arborescences d'expression. Le fait est que l'interface IQueryable hérite de l'interface IEnumerable de sorte que si elle représente une requête, les résultats de cette requête peuvent être énumérés. L'énumération entraîne l'exécution de l'arborescence d'expression associée à un objet IQueryable.
Arman McHitarian
24

En général, vous souhaitez conserver le type statique d'origine de la requête jusqu'à ce qu'il soit important.

Pour cette raison, vous pouvez définir votre variable comme «var» au lieu de l'un IQueryable<>ou de l'autre IEnumerable<>et vous saurez que vous ne changez pas le type.

Si vous commencez avec un IQueryable<>, vous voulez généralement le conserver comme IQueryable<>jusqu'à ce qu'il y ait une raison impérieuse de le changer. La raison en est que vous souhaitez fournir au processeur de requêtes autant d'informations que possible. Par exemple, si vous n'utilisez que 10 résultats (vous avez appelé Take(10)), vous voulez que SQL Server le sache afin qu'il puisse optimiser ses plans de requête et vous envoyer uniquement les données que vous utiliserez.

Une raison impérieuse de changer le type de IQueryable<>à IEnumerable<>pourrait être que vous appelez une fonction d'extension que l'implémentation de IQueryable<>dans votre objet particulier ne peut pas gérer ou gère de manière inefficace. Dans ce cas, vous souhaiterez peut-être convertir le type en IEnumerable<>(en l'assignant à une variable de type IEnumerable<>ou en utilisant la AsEnumerableméthode d'extension par exemple) afin que les fonctions d'extension que vous appelez finissent par être celles de la Enumerableclasse au lieu de la Queryableclasse.

AJS
la source
18

Il existe un article de blog avec un bref exemple de code source sur la façon dont une mauvaise utilisation IEnumerable<T>peut avoir un impact considérable sur les performances des requêtes LINQ: Entity Framework: IQueryable vs. IEnumerable .

Si nous creusons plus profondément et examinons les sources, nous pouvons voir qu'il existe évidemment différentes méthodes d'extension pour IEnumerable<T>:

// Type: System.Linq.Enumerable
// Assembly: System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
// Assembly location: C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Core.dll
public static class Enumerable
{
    public static IEnumerable<TSource> Where<TSource>(
        this IEnumerable<TSource> source, 
        Func<TSource, bool> predicate)
    {
        return (IEnumerable<TSource>) 
            new Enumerable.WhereEnumerableIterator<TSource>(source, predicate);
    }
}

et IQueryable<T>:

// Type: System.Linq.Queryable
// Assembly: System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
// Assembly location: C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Core.dll
public static class Queryable
{
    public static IQueryable<TSource> Where<TSource>(
        this IQueryable<TSource> source, 
        Expression<Func<TSource, bool>> predicate)
    {
        return source.Provider.CreateQuery<TSource>(
            Expression.Call(
                null, 
                ((MethodInfo) MethodBase.GetCurrentMethod()).MakeGenericMethod(
                    new Type[] { typeof(TSource) }), 
                    new Expression[] 
                        { source.Expression, Expression.Quote(predicate) }));
    }
}

Le premier retourne l'itérateur énumérable, et le second crée une requête via le fournisseur de requêtes, spécifié dans la IQueryablesource.

Olexander Ivanitskyi
la source
11

J'ai récemment rencontré un problème avec IEnumerablev IQueryable. L'algorithme utilisé a d'abord effectué une IQueryablerequête pour obtenir un ensemble de résultats. Celles-ci ont ensuite été passées à une foreachboucle, avec les éléments instanciés en tant que classe Entity Framework (EF). Cette classe EF a ensuite été utilisée dans la fromclause d'une requête Linq to Entity, provoquant le résultat IEnumerable.

Je suis assez nouveau pour EF et Linq for Entities, il a donc fallu un certain temps pour comprendre quel était le goulot d'étranglement. À l'aide de MiniProfiling, j'ai trouvé la requête, puis j'ai converti toutes les opérations individuelles en une seule IQueryablerequête Linq for Entities. L' exécution a IEnumerableduré 15 secondes et IQueryable0,5 seconde. Il y avait trois tables impliquées et, après avoir lu ceci, je crois que la IEnumerablerequête formait en fait un produit croisé à trois tables et filtrait les résultats.

Essayez d'utiliser IQueryables comme règle empirique et profilez votre travail pour rendre vos changements mesurables.

sscheider
la source
la raison en était que les expressions IQueryable sont converties en SQL natif dans EF et sont exécutées directement dans la base de données tandis que les listes IEnumerable sont des objets en mémoire. Ils sont récupérés à partir de la base de données à un moment donné lorsque vous appelez des fonctions d'agrégation comme Count, Sum ou n'importe quel To ... et fonctionnent ensuite en mémoire. IQueryables sont également bloqués dans la mémoire une fois que vous avez appelé l'une de ces API, mais sinon, vous pouvez passer l'expression dans la pile des couches et jouer avec les filtres jusqu'à l'appel de l'API. Un DAL bien conçu comme un référentiel bien conçu résoudra ce genre de problèmes;)
Arman McHitarian
10

Je voudrais clarifier certaines choses en raison de réponses apparemment contradictoires (principalement entourant IEnumerable).

(1) IQueryableétend l' IEnumerableinterface. (Vous pouvez envoyer un IQueryableà quelque chose qui attend IEnumerablesans erreur.)

(2) Les deux IQueryableet IEnumerableLINQ tentent un chargement paresseux lors de l'itération sur l'ensemble de résultats. (Notez que l'implémentation peut être vue dans les méthodes d'extension d'interface pour chaque type.)

En d'autres termes, IEnumerablesne sont pas exclusivement "en mémoire". IQueryablesne sont pas toujours exécutés sur la base de données. IEnumerabledoit charger les choses en mémoire (une fois récupéré, peut-être paresseusement) car il n'a pas de fournisseur de données abstrait. IQueryabless'appuyer sur un fournisseur abstrait (comme LINQ-to-SQL), bien qu'il puisse également s'agir du fournisseur en mémoire .NET.

Exemple d'utilisation

(a) Récupérer la liste des enregistrements à IQueryablepartir du contexte EF. (Aucun enregistrement n'est en mémoire.)

(b) Passez IQueryableà une vue dont le modèle est IEnumerable. (Valide. IQueryableS'étend IEnumerable.)

(c) Parcourez et accédez aux enregistrements de l'ensemble de données, aux entités enfants et aux propriétés à partir de la vue. (Peut provoquer des exceptions!)

Problèmes possibles

(1) Les IEnumerabletentatives de chargement différé et votre contexte de données ont expiré. Exception levée car le fournisseur n'est plus disponible.

(2) Les proxys d'entité Entity Framework sont activés (par défaut) et vous tentez d'accéder à un objet (virtuel) associé avec un contexte de données expiré. Identique à (1).

(3) Plusieurs jeux de résultats actifs (MARS). Si vous parcourez le IEnumerabledans un foreach( var record in resultSet )bloc et tentez simultanément d'accéder record.childEntity.childProperty, vous pouvez vous retrouver avec MARS en raison du chargement paresseux de l'ensemble de données et de l'entité relationnelle. Cela provoquera une exception s'il n'est pas activé dans votre chaîne de connexion.

Solution

  • J'ai constaté que l'activation de MARS dans la chaîne de connexion fonctionne de manière non fiable. Je vous suggère d'éviter MARS à moins qu'il ne soit bien compris et explicitement souhaité.

Exécutez la requête et stockez les résultats en appelant resultList = resultSet.ToList() Cela semble être le moyen le plus simple de vous assurer que vos entités sont en mémoire.

Dans les cas où vous accédez à des entités liées, vous pouvez toujours avoir besoin d'un contexte de données. Soit cela, soit vous pouvez désactiver les proxys d'entité et Includeles entités explicitement liées de votre DbSet.


la source
9

La principale différence entre «IEnumerable» et «IQueryable» concerne l'emplacement d'exécution de la logique de filtrage. L'un s'exécute côté client (en mémoire) et l'autre s'exécute sur la base de données.

Par exemple, nous pouvons considérer un exemple où nous avons 10 000 enregistrements pour un utilisateur dans notre base de données et disons seulement 900 sur qui sont des utilisateurs actifs, donc dans ce cas, si nous utilisons «IEnumerable», il charge d'abord les 10 000 enregistrements en mémoire et applique ensuite le filtre IsActive sur celui-ci qui renvoie finalement les 900 utilisateurs actifs.

Alors que d'autre part sur le même cas si nous utilisons «IQueryable», il appliquera directement le filtre IsActive sur la base de données qui directement à partir de là retournera les 900 utilisateurs actifs.

Lien de référence

Tabish Usman
la source
lequel est optimisé et léger en termes de performances?
Sitecore Sam
@Sam "IQueryable" est plus préféré en termes d'optimisation et de légèreté.
Tabish Usman
6

Nous pouvons utiliser les deux de la même manière, et ils ne sont différents que dans les performances.

IQueryable s'exécute uniquement sur la base de données de manière efficace. Cela signifie qu'il crée une requête de sélection entière et n'obtient que les enregistrements associés.

Par exemple, nous voulons prendre les 10 premiers clients dont le nom commence par «Nimal». Dans ce cas, la requête de sélection sera générée en tant que select top 10 * from Customer where name like ‘Nimal%’.

Mais si nous utilisions IEnumerable, la requête serait comme select * from Customer where name like ‘Nimal%’et les dix premiers seront filtrés au niveau du codage C # (il récupère tous les enregistrements clients de la base de données et les transmet en C #).

user3710357
la source
5

En plus des 2 premières bonnes réponses (par driis et par Jacob):

L'interface IEnumerable se trouve dans l'espace de noms System.Collections.

L'objet IEnumerable représente un ensemble de données en mémoire et ne peut avancer sur ces données que vers l'avant. La requête représentée par l'objet IEnumerable est exécutée immédiatement et complètement, de sorte que l'application reçoit rapidement les données.

Lorsque la requête est exécutée, IEnumerable charge toutes les données et si nous devons les filtrer, le filtrage lui-même est effectué côté client.

L'interface IQueryable se trouve dans l'espace de noms System.Linq.

L'objet IQueryable fournit un accès à distance à la base de données et vous permet de parcourir les données soit dans un ordre direct du début à la fin, soit dans l'ordre inverse. Dans le processus de création d'une requête, l'objet renvoyé est IQueryable, la requête est optimisée. Par conséquent, moins de mémoire est consommée lors de son exécution, moins de bande passante réseau, mais en même temps, elle peut être traitée un peu plus lentement qu'une requête qui renvoie un objet IEnumerable.

Que choisir?

Si vous avez besoin de l'ensemble des données renvoyées, il est préférable d'utiliser IEnumerable, qui fournit la vitesse maximale.

Si vous n'avez PAS besoin de l'ensemble des données renvoyées, mais uniquement de certaines données filtrées, il est préférable d'utiliser IQueryable.

Gleb B
la source
0

En plus de ce qui précède, il est intéressant de noter que vous pouvez obtenir des exceptions si vous utilisez IQueryableau lieu de IEnumerable:

Ce qui suit fonctionne bien si productsest un IEnumerable:

products.Skip(-4);

Cependant, si productsest un IQueryableet essaie d'accéder aux enregistrements d'une table de base de données, vous obtiendrez cette erreur:

Le décalage spécifié dans une clause OFFSET peut ne pas être négatif.

En effet, la requête suivante a été créée:

SELECT [p].[ProductId]
FROM [Products] AS [p]
ORDER BY (SELECT 1)
OFFSET @__p_0 ROWS

et OFFSET ne peut pas avoir de valeur négative.

David Klempfner
la source