Quelle est la différence entre IQueryable <T> et IEnumerable <T>?


Réponses:


258

Tout d'abord, étend l' interface, donc tout ce que vous pouvez faire avec un "simple" , vous pouvez également le faire avec un .IQueryable<T> IEnumerable<T>IEnumerable<T>IQueryable<T>

IEnumerable<T>juste a une GetEnumerator()méthode qui retourne un Enumerator<T>pour lequel vous pouvez appeler sa MoveNext()méthode pour itérer à travers une séquence de T .

Ce IQueryable<T>qui IEnumerable<T> n'a pas ce sont deux propriétés en particulier: une qui pointe vers un fournisseur de requête (par exemple, un fournisseur LINQ to SQL) et une autre pointant vers une expression de requête représentant l' IQueryable<T>objet comme une arborescence de syntaxe abstraite traversable par le runtime qui peut être compris par le fournisseur de requêtes donné (pour la plupart, vous ne pouvez pas donner une expression LINQ to SQL à un fournisseur LINQ to Entities sans qu'une exception ne soit levée).

L'expression peut simplement être une expression constante de l'objet lui-même ou une arborescence plus complexe d'un ensemble composé d'opérateurs et d'opérandes de requête. Le IQueryProvider.Execute()ou les IQueryProvider.CreateQuery()méthodes du fournisseur de requête sont appelées avec une expression qui lui est transmise, puis un résultat de requête ou un autre IQueryableest retourné, respectivement.


8
Y a-t-il un avantage à utiliser AsQueryable?
Jordan

6
Le seul avantage est la commodité. AsQueryable()va simplement transtyper un énumérable en un interrogeable et le retourner s'il implémente l' IQueryableinterface, sinon il l'enveloppe dans un ConstantExpression, auquel il est fait référence dans un EnumerableQueryobjet renvoyé .
Mark Cidade


1
Vaut la peine de lire cet article
JenonD

Le lien @JenonD est mort, voici le chemin de retour: web.archive.org/web/20160904162931/http://www.dotnet-tricks.com/…
majjam

201

La principale différence est que les opérateurs LINQ pour IQueryable<T>prendre des Expressionobjets au lieu de délégués, ce qui signifie que la logique de requête personnalisée qu'il reçoit, par exemple un prédicat ou un sélecteur de valeur, se présente sous la forme d'un arbre d'expression au lieu d'un délégué à une méthode.

  • IEnumerable<T> est idéal pour travailler avec des séquences qui sont itérées en mémoire, mais
  • IQueryable<T> permet des éléments de mémoire insuffisante comme une source de données distante, comme une base de données ou un service Web.

Exécution de la requête:

  • Lorsque l'exécution d'une requête va être effectuée "en cours" , il suffit généralement du code (en tant que code) pour exécuter chaque partie de la requête.

  • Lorsque l'exécution sera effectuée hors processus , la logique de la requête doit être représentée dans les données de sorte que le fournisseur LINQ puisse la convertir sous la forme appropriée pour l'exécution hors mémoire - qu'il s'agisse d'une requête LDAP, SQL ou autre.

Plus dans:

http://www.codeproject.com/KB/cs/646361/WhatHowWhere.jpg


14
J'aime la mention des opérations de mémoire insuffisante. Il clarifie une réelle différence pratique d'utilisation.
Ishmael Smyrnow

2
Au lieu de prendre des délégués comme paramètres comme la méthode IEnumerable <T> Where, IQueryable <T> prendra les paramètres Expression <TDelegate>. Nous ne transmettons pas de code à IQueryable <T>, nous transmettons des arborescences d'expression (code en tant que données) pour que le fournisseur LINQ les analyse. C # 3.0 et LINQ
Lu55

quelque chose avec votre lien d'image, ce ne est pas rendu dans le corps après pour une raison quelconque codeproject.com/KB/cs/646361/WhatHowWhere.jpg
jbooker

@joey Pourtant, je vois cette image très bien dans cette réponse: i.stack.imgur.com/2DAqv.jpg
VonC

190

Ceci est une belle vidéo sur YouTube qui montre comment ces interfaces diffèrent, vaut le détour.

Ci-dessous, une longue réponse descriptive.

Le premier point important à retenir est l' IQueryableinterface héritée de IEnumerable, donc tout ce qui IEnumerablepeut faire IQueryablepeut aussi le faire.

entrez la description de l'image ici

Il existe de nombreuses différences, mais discutons de la grande différence qui fait la plus grande différence. IEnumerableest utile lorsque votre collection est chargée à l'aide du LINQframework Entity et que vous souhaitez appliquer un filtre sur la collection.

Considérez le code simple ci-dessous qui utilise IEnumerableavec le framework d'entité. Il utilise un Wherefiltre pour obtenir les enregistrements dont il EmpIds'agit 2.

EmpEntities ent = new EmpEntities();
IEnumerable<Employee> emp = ent.Employees; 
IEnumerable<Employee> temp = emp.Where(x => x.Empid == 2).ToList<Employee>();

C'est là que le filtre est exécuté du côté client où se trouve le IEnumerablecode. En d'autres termes, toutes les données sont extraites de la base de données, puis sur le client, ses analyses et obtient l'enregistrement avec EmpIdest 2.

entrez la description de l'image ici

Mais maintenant voir le code ci - dessous nous avons changé IEnumerablepour IQueryable. Il crée une requête SQL côté serveur et seules les données nécessaires sont envoyées côté client.

EmpEntities ent = new EmpEntities();
IQueryable<Employee> emp = ent.Employees;
IQueryable<Employee> temp =  emp.Where(x => x.Empid == 2).ToList<Employee>();

entrez la description de l'image ici

Ainsi, la différence entre IQueryableet IEnumerableconcerne l'emplacement d'exécution de la logique de filtrage. L'un s'exécute côté client et l'autre s'exécute sur la base de données.

Donc, si vous travaillez uniquement avec la collecte de données en mémoire IEnumerableest un bon choix, mais si vous souhaitez interroger la collecte de données qui est connectée à la base de données `IQueryable est un meilleur choix car il réduit le trafic réseau et utilise la puissance du langage SQL.


Salut, merci beaucoup pour cette merveilleuse explication. Je comprends pourquoi IQueryable est un meilleur choix pour les données "out-of-memory" mais j'ai du mal à comprendre pourquoi IEnumerable est meilleur pour les données "in-memory"? Je pense toujours qu'il vaut mieux obtenir des données filtrées que d'obtenir des données et d'appliquer un filtre.
Imad

quand c'est "en mémoire", ça n'a pas vraiment d'importance. les données sont déjà dans la mémoire, l'heure exacte à laquelle elles sont filtrées n'a pas d'importance.
Roni Axelrad

@Imad Par exemple, la projection de données en convertissant l'entité DateTimeOffset en DateTime ne peut pas être effectuée en utilisant IQueryable ou avec EntityFunctions. La meilleure façon consiste à AsEnumerable () l'objet entité, puis Select () dans un viewmodel qui contient le DateTime. Ce processus utilise des fonctions en mémoire.
Jeff

57

IEnumerable: IEnumerable est le mieux adapté pour travailler avec une collection en mémoire (ou des requêtes locales). IEnumerable ne se déplace pas entre les éléments, il s'agit uniquement de la collecte vers l'avant.

IQueryable: IQueryable convient le mieux à une source de données distante, comme une base de données ou un service Web (ou des requêtes distantes). IQueryable est une fonctionnalité très puissante qui permet une variété de scénarios d'exécution différée intéressants (comme les requêtes basées sur la pagination et la composition).

Donc, lorsque vous devez simplement parcourir la collection en mémoire, utilisez IEnumerable, si vous avez besoin de manipuler la collection comme Dataset et d'autres sources de données, utilisez IQueryable


3
IEnumerable n'utilise-t-il pas l'exécution différée?
Ian Warburton

3
L'exécution différée est disponible à la fois dans IEnumerable et IQueryable. D'autres informations intéressantes peuvent être trouvées ici: stackoverflow.com/questions/2876616/…
Ignacio Hagopian

18

En d'autres termes, une autre différence majeure est que IEnumerable exécute la requête de sélection côté serveur, charge les données en mémoire côté client, puis filtre les données tandis qu'IQueryable exécute la requête de sélection côté serveur avec tous les filtres.


17

Dans la vraie vie, si vous utilisez un ORM comme LINQ-to-SQL

  • Si vous créez un IQueryable, la requête peut être convertie en SQL et exécutée sur le serveur de base de données
  • Si vous créez un IEnumerable, toutes les lignes seront extraites en mémoire en tant qu'objets avant d'exécuter la requête.

Dans les deux cas, si vous n'appelez pas ToList()ou ToArray()alors la requête sera exécutée à chaque fois qu'elle est utilisée, par exemple, vous avez un IQueryable<T>et vous en remplissez 4 zones de liste, puis la requête sera exécutée 4 fois sur la base de données.

Aussi, si vous étendez votre requête:

q.Where(x.name = "a").ToList()

Ensuite, avec un IQueryable, le SQL généré contiendra "où nom =" a ", mais avec un IEnumerable, de nombreux autres rôles seront retirés de la base de données, puis la vérification x.name =" a "sera effectuée par .NET.


10

IEnumerable fait référence à une collection, mais IQueryable n'est qu'une requête et elle sera générée dans un arbre d'expression. Nous exécuterons cette requête pour obtenir des données de la base de données.


8

Le petit test mentionné ci-dessous pourrait vous aider à comprendre un aspect de la différence entre IQueryable<T>et IEnumerable<T>. J'ai reproduit cette réponse de ce post où j'essayais d'ajouter des corrections au post de quelqu'un d'autre

J'ai créé la structure suivante dans DB (script DDL):

CREATE TABLE [dbo].[Employee]([PersonId] [int] NOT NULL PRIMARY KEY,[Salary] [int] NOT NULL)

Voici le script d'insertion d'enregistrement (script DML):

INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(1, 20)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(2, 30)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(3, 40)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(4, 50)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(5, 60)
GO

Maintenant, mon objectif était simplement d'obtenir les 2 meilleurs enregistrements de la Employeetable dans la base de données. J'ai ajouté un élément ADO.NET Entity Data Model dans mon application console pointant vers la Employeetable dans ma base de données et j'ai commencé à écrire des requêtes LINQ.

Code pour l'itinéraire IQueryable :

using (var efContext = new EfTestEntities())
{
    IQueryable<int> employees = from e in efContext.Employees  select e.Salary;
    employees = employees.Take(2);

    foreach (var item in employees)
    {
        Console.WriteLine(item);
    }
}

Lorsque j'ai commencé à exécuter ce programme, j'avais également démarré une session de SQL Query profiler sur mon instance SQL Server et voici le résumé de l'exécution:

  1. Nombre total de requêtes lancées: 1
  2. Texte de la requête: SELECT TOP (2) [c].[Salary] AS [Salary] FROM [dbo].[Employee] AS [c]

C'est juste que IQueryablec'est assez intelligent pour appliquer la Top (2)clause du côté serveur de base de données lui-même, de sorte qu'il n'apporte que 2 enregistrements sur 5 sur le fil. Aucun autre filtrage en mémoire n'est nécessaire du tout côté ordinateur client.

Code pour la route IEnumerable :

using (var efContext = new EfTestEntities())
{
    IEnumerable<int> employees = from e in efContext.Employees  select e.Salary;
    employees = employees.Take(2);

    foreach (var item in employees)
    {
        Console.WriteLine(item);
    }
}

Résumé de l'exécution dans ce cas:

  1. Nombre total de requêtes lancées: 1
  2. Texte de requête capturé dans le profileur SQL: SELECT [Extent1].[Salary] AS [Salary] FROM [dbo].[Employee] AS [Extent1]

Maintenant, la chose est IEnumerableapportée tous les 5 enregistrements présents dans le Salarytableau, puis effectué un filtrage en mémoire sur l'ordinateur client pour obtenir les 2 meilleurs enregistrements. Donc, plus de données (3 enregistrements supplémentaires dans ce cas) ont été transférées inutilement sur le fil.


7

Voici ce que j'ai écrit sur un article similaire (sur ce sujet). (Et non, je ne me cite généralement pas, mais ce sont de très bons articles.)

"Cet article est utile: IQueryable vs IEnumerable dans LINQ-to-SQL .

Citant cet article, «Conformément à la documentation MSDN, les appels effectués sur IQueryable fonctionnent en créant à la place l'arborescence des expressions internes. "Ces méthodes qui étendent IQueryable (Of T) n'effectuent aucune requête directement. Au lieu de cela, leur fonctionnalité consiste à créer un objet Expression, qui est une arborescence d'expression qui représente la requête cumulative." '

Les arbres d'expression sont une construction très importante en C # et sur la plate-forme .NET. (Ils sont importants en général, mais C # les rend très utiles.) Pour mieux comprendre la différence, je recommande de lire ici les différences entre les expressions et les instructions dans la spécification officielle C # 5.0. Pour les concepts théoriques avancés qui se ramifient en calcul lambda, les expressions permettent la prise en charge des méthodes en tant qu'objets de première classe. La différence entre IQueryable et IEnumerable est centrée autour de ce point. IQueryable construit des arborescences d'expression, contrairement à IEnumerable, du moins pas en termes généraux pour ceux d'entre nous qui ne travaillent pas dans les laboratoires secrets de Microsoft.

Voici un autre article très utile qui détaille les différences d'un point de vue push / pull. (Par «pousser» vs «tirer», je fais référence à la direction du flux de données. Techniques de programmation réactive pour .NET et C #

Voici un très bon article qui détaille les différences entre les lambdas d'instruction et les lambdas d'expression et traite plus en détail des concepts d'expression tress: Revisiter les délégués C #, les arborescences d'expression et les instructions lambda par rapport aux expressions lambda. . "


6

Nous utilisons IEnumerableet IQueryablepour manipuler les données extraites de la base de données. IQueryablehérite de IEnumerable, IQueryablecontient donc toutes les IEnumerablefonctionnalités. La principale différence entre IQueryableet IEnumerableest que la IQueryablerequête est exécutée avec des filtres, tandis que IEnumerablela requête est exécutée en premier, puis elle filtre les données en fonction des conditions.

Trouvez une différenciation plus détaillée ci-dessous:

IEnumerable

  1. IEnumerableexiste dans l' System.Collectionsespace de noms
  2. IEnumerable exécuter une requête de sélection côté serveur, charger les données en mémoire côté client, puis filtrer les données
  3. IEnumerable convient pour interroger des données à partir de collections en mémoire comme List, Array
  4. IEnumerable est bénéfique pour les requêtes LINQ to Object et LINQ to XML

IQueryable

  1. IQueryableexiste dans l' System.Linqespace de noms
  2. IQueryable exécute une «requête de sélection» côté serveur avec tous les filtres
  3. IQueryable convient pour interroger des données à partir de collections hors mémoire (comme une base de données distante, un service)
  4. IQueryable est bénéfique pour les requêtes LINQ to SQL

So IEnumerableest généralement utilisé pour traiter les collections en mémoire, tandis que, IQueryableest généralement utilisé pour manipuler les collections.



2

IQueryable est plus rapide que IEnumerable si nous avons affaire à d'énormes quantités de données de la base de données car, IQueryable obtient uniquement les données requises de la base de données où IEnumerable obtient toutes les données indépendamment de la nécessité de la base de données


0

ienumerable: quand nous voulons traiter la mémoire inprocess, c'est-à-dire sans connexion de données iqueryable: quand traiter avec le serveur SQL, c'est-à-dire avec la connexion de données ilist: opérations comme ajouter un objet, supprimer un objet, etc.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.