Was ist der Unterschied zwischen IQueryable <T> und IEnumerable <T>?

Antworten:

258

Zunächst einmal erweitert die Schnittstelle, so alles , was Sie tun können , mit einem „plain“ , können Sie auch mit einem tun .IQueryable<T> IEnumerable<T>IEnumerable<T>IQueryable<T>

IEnumerable<T>hat nur eine GetEnumerator()Methode, die eine zurückgibt, Enumerator<T>für die Sie ihre MoveNext()Methode aufrufen können , um eine Folge von T zu durchlaufen .

Was dies nichtIQueryable<T> hat, sind insbesondere zwei Eigenschaften - eine, die auf einen Abfrageanbieter verweist (z. B. einen LINQ to SQL-Anbieter), und eine andere, die auf einen Abfrageausdruck verweist, der das Objekt als einen zur Laufzeit durchlaufbaren abstrakten Syntaxbaum darstellt, der sein kann vom angegebenen Abfrageanbieter verstanden (zum größten Teil können Sie einem LINQ to Entities-Anbieter keinen LINQ to SQL-Ausdruck geben, ohne dass eine Ausnahme ausgelöst wird).IEnumerable<T> IQueryable<T>

Der Ausdruck kann einfach ein konstanter Ausdruck des Objekts selbst oder ein komplexerer Baum einer zusammengesetzten Menge von Abfrageoperatoren und Operanden sein. Die IQueryProvider.Execute()oder IQueryProvider.CreateQuery()Methoden des Abfrageanbieters werden mit einem an ihn übergebenen Ausdruck aufgerufen , und dann wird entweder ein Abfrageergebnis oder ein anderes IQueryablezurückgegeben.

Mark Cidade
quelle
8
Gibt es einen Vorteil bei der Verwendung von AsQueryable?
Jordanien
6
Der einzige Vorteil ist die Bequemlichkeit. AsQueryable()wandelt nur eine Aufzählung in eine abfragbare um und gibt sie zurück, wenn sie die IQueryableSchnittstelle implementiert , andernfalls wird sie in eine eingeschlossen ConstantExpression, auf die in einem zurückgegebenen EnumerableQueryObjekt verwiesen wird.
Mark Cidade
3
Verwandte Frage: IEnumerable <T> und IQueryable <T> Klarstellung?
Christopher Stevenson
1
Es lohnt sich, diesen Artikel zu
JenonD
@ JenD Link ist tot, hier ist die Wayback-Maschine: web.archive.org/web/20160904162931/http://www.dotnet-tricks.com/…
Majjam
201

Der Hauptunterschied besteht darin, dass die LINQ-Operatoren für IQueryable<T>Take- ExpressionObjekte anstelle von Delegaten, dh die empfangene benutzerdefinierte Abfragelogik, z. B. ein Prädikat oder ein Werteselektor, in Form eines Ausdrucksbaums anstelle eines Delegaten an eine Methode vorliegen.

  • IEnumerable<T> eignet sich hervorragend für die Arbeit mit Sequenzen, die im Speicher iteriert werden, aber
  • IQueryable<T> Ermöglicht nicht genügend Arbeitsspeicher wie eine entfernte Datenquelle wie eine Datenbank oder einen Webdienst.

Abfrageausführung:

  • Wenn die Ausführung einer Abfrage "in Bearbeitung" durchgeführt werden soll , ist normalerweise nur der Code (als Code) erforderlich, um jeden Teil der Abfrage auszuführen.

  • Wenn die Ausführung außerhalb des Prozesses ausgeführt wird , muss die Logik der Abfrage in Daten dargestellt werden, damit der LINQ-Anbieter sie in die entsprechende Form für die Ausführung außerhalb des Speichers konvertieren kann - unabhängig davon, ob es sich um eine LDAP-Abfrage handelt. SQL oder was auch immer.

Mehr in:

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

VonC
quelle
14
Ich mag die Erwähnung von Operationen mit nicht genügend Speicher. Es verdeutlicht einen echten praktischen Unterschied in der Verwendung.
Ishmael Smyrnow
2
Anstatt Delegaten als Parameter wie die IEnumerable <T> Where-Methode zu verwenden, verwendet IQueryable <T> Expression <TDelegate> -Parameter. Wir übergeben keinen Code an IQueryable <T>, sondern übergeben Ausdrucksbäume (Code als Daten), die der LINQ-Anbieter analysieren soll. C # 3.0 und LINQ
Lu55
Etwas ist mit Ihrem Bild-Link los, es wird
jbooker
@joey Dennoch sehe ich das Bild in dieser Antwort ganz gut: i.stack.imgur.com/2DAqv.jpg
VonC
190

Dies ist ein schönes Video auf Youtube das zeigt, wie sich diese Schnittstellen unterscheiden, eine Uhr wert.

Nachfolgend finden Sie eine lange beschreibende Antwort darauf.

Der erste wichtige Punkt, an den Sie sich erinnern sollten, ist, dass die IQueryableSchnittstelle von erbt. IEnumerableWas also alles IEnumerablekann, IQueryablekann auch.

Geben Sie hier die Bildbeschreibung ein

Es gibt viele Unterschiede, aber lassen Sie uns über den einen großen Unterschied diskutieren, der den größten Unterschied macht. IEnumerableDie Benutzeroberfläche ist nützlich, wenn Ihre Sammlung mit LINQoder Entity Framework geladen wird und Sie einen Filter auf die Sammlung anwenden möchten.

Betrachten Sie den folgenden einfachen Code, der IEnumerablemit dem Entity Framework verwendet wird. Es wird ein WhereFilter verwendet, um Datensätze abzurufen, deren EmpIdist 2.

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

Hier wird der Filter auf der Clientseite ausgeführt, auf der sich der IEnumerableCode befindet. Mit anderen Worten, alle Daten werden aus der Datenbank abgerufen und dann auf dem Client gescannt und der Datensatz mit EmpIdis abgerufen 2.

Geben Sie hier die Bildbeschreibung ein

Aber sehen Sie jetzt den Code unten haben wir geändert IEnumerablezu IQueryable. Es wird eine SQL-Abfrage auf der Serverseite erstellt und nur die erforderlichen Daten werden an die Clientseite gesendet.

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

Geben Sie hier die Bildbeschreibung ein

Also der Unterschied zwischen IQueryableundIEnumerable besteht also darin, wo die Filterlogik ausgeführt wird. Einer wird auf der Clientseite und der andere auf der Datenbank ausgeführt.

Wenn Sie also nur mit speicherinterner Datenerfassung arbeiten, IEnumerableist dies eine gute Wahl, wenn Sie jedoch eine Datenerfassung abfragen möchten, die mit der Datenbank verbunden ist. IQueryable ist eine bessere Wahl, da es den Netzwerkverkehr reduziert und die Leistung der SQL-Sprache nutzt.

Shivprasad Koirala
quelle
Hallo, vielen Dank für die wundervolle Erklärung. Ich verstehe, warum IQueryable die bessere Wahl für Daten mit "Nicht-Speicher" ist, aber ich habe Schwierigkeiten zu verstehen, warum IEnumerable für Daten mit "Nicht-Speicher" besser ist. Ich denke immer noch, dass es besser ist, gefilterte Daten zu erhalten, als Daten abzurufen und Filter anzuwenden.
Imad
Wenn es "in-memory" ist, spielt es keine Rolle. Die Daten befinden sich bereits im Speicher. Wann genau sie gefiltert werden, spielt keine Rolle.
Roni Axelrad
@Imad Das Projizieren von Daten durch Konvertieren der Entität DateTimeOffset in DateTime kann beispielsweise nicht mit IQueryable oder mit EntityFunctions durchgeführt werden. Der beste Weg ist, das Entitätsobjekt AsEnumerable () und dann Select () in ein Ansichtsmodell zu integrieren, das die DateTime enthält. Dieser Prozess verwendet In-Memory-Funktionen.
Jeff Li
57

IEnumerable: IEnumerable eignet sich am besten für die Arbeit mit In-Memory-Sammlungen (oder lokalen Abfragen). IEnumerable bewegt sich nicht zwischen Elementen, sondern ist nur eine Vorwärtssammlung.

IQueryable: IQueryable eignet sich am besten für Remote-Datenquellen wie Datenbanken oder Webdienste (oder Remote-Abfragen). IQueryable ist eine sehr leistungsstarke Funktion, die eine Vielzahl interessanter Szenarien für die verzögerte Ausführung ermöglicht (z. B. Paging- und kompositionsbasierte Abfragen).

Wenn Sie also einfach die In-Memory-Sammlung durchlaufen müssen, verwenden Sie IEnumerable. Wenn Sie die Sammlung wie Dataset und andere Datenquellen bearbeiten möchten, verwenden Sie IQueryable

Talha
quelle
3
Verwendet IEnumerable nicht die verzögerte Ausführung?
Ian Warburton
3
Die verzögerte Ausführung ist sowohl in IEnumerable als auch in IQueryable verfügbar. Weitere interessante Informationen finden Sie hier: stackoverflow.com/questions/2876616/…
Ignacio Hagopian
18

Mit einfachen Worten, ein weiterer wesentlicher Unterschied besteht darin, dass IEnumerable eine Auswahlabfrage auf der Serverseite ausführt, Daten auf der Clientseite in den Speicher lädt und dann Daten filtert, während IQueryable eine Auswahlabfrage auf der Serverseite mit allen Filtern ausführt.

BEIM
quelle
17

Im wirklichen Leben, wenn Sie ein ORM wie LINQ-to-SQL verwenden

  • Wenn Sie eine IQueryable erstellen, wird die Abfrage möglicherweise in SQL konvertiert und auf dem Datenbankserver ausgeführt
  • Wenn Sie eine IEnumerable erstellen, werden alle Zeilen als Objekte in den Speicher gezogen, bevor die Abfrage ausgeführt wird.

In beiden Fällen wird die Abfrage viermal für die Datenbank ausgeführt, wenn Sie eine Abfrage nicht aufrufen ToList()oder ToArray()dann bei jeder Verwendung ausgeführt werden. Wenn Sie beispielsweise eine Abfrage haben IQueryable<T>und 4 Listenfelder daraus ausfüllen.

Auch wenn Sie Ihre Anfrage erweitern:

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

Dann enthält die generierte SQL mit einem IQueryable "where name =" a ", aber mit einem IEnumerable werden viel mehr Rollen aus der Datenbank zurückgezogen, und die Prüfung x.name =" a "wird von .NET durchgeführt.

Ian Ringrose
quelle
10

IEnumerable bezieht sich auf eine Sammlung, IQueryable ist jedoch nur eine Abfrage und wird in einem Ausdrucksbaum generiert. Wir führen diese Abfrage aus, um Daten aus der Datenbank abzurufen.

seyed
quelle
8

Der unten erwähnte kleine Test kann Ihnen helfen, einen Aspekt des Unterschieds zwischen IQueryable<T>und zu verstehen IEnumerable<T>. Ich habe diese Antwort aus diesem Beitrag reproduziert, in dem ich versucht habe, Korrekturen zum Beitrag eines anderen hinzuzufügen

Ich habe folgende Struktur in DB (DDL-Skript) erstellt:

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

Hier ist das Skript zum Einfügen von Datensätzen (DML-Skript):

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

Mein Ziel war es nun einfach, die Top 2 Datensätze aus der EmployeeTabelle in der Datenbank zu erhalten. Ich habe meiner Konsolenanwendung ein ADO.NET-Entitätsdatenmodellelement hinzugefügt, das auf eine EmployeeTabelle in meiner Datenbank verweist, und mit dem Schreiben von LINQ-Abfragen begonnen.

Code für IQueryable Route :

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);
    }
}

Als ich dieses Programm ausführte, hatte ich auch eine Sitzung des SQL Query-Profilers auf meiner SQL Server-Instanz gestartet. Hier ist die Zusammenfassung der Ausführung:

  1. Gesamtzahl der abgefeuerten Abfragen: 1
  2. Abfragetext: SELECT TOP (2) [c].[Salary] AS [Salary] FROM [dbo].[Employee] AS [c]

Es ist nur IQueryableklug genug, die Top (2)Klausel auf der Seite des Datenbankservers selbst anzuwenden, sodass nur 2 von 5 Datensätzen über das Netzwerk übertragen werden. Eine weitere In-Memory-Filterung ist auf der Client-Computerseite überhaupt nicht erforderlich.

Code für IEnumerable Route :

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);
    }
}

Zusammenfassung der Ausführung in diesem Fall:

  1. Gesamtzahl der abgefeuerten Abfragen: 1
  2. Im SQL-Profiler erfasster Abfragetext: SELECT [Extent1].[Salary] AS [Salary] FROM [dbo].[Employee] AS [Extent1]

Jetzt werden IEnumerablealle 5 in der SalaryTabelle vorhandenen Datensätze angezeigt und anschließend eine speicherinterne Filterung auf dem Client-Computer durchgeführt, um die beiden besten Datensätze zu erhalten. So wurden unnötigerweise mehr Daten (in diesem Fall 3 zusätzliche Datensätze) über das Kabel übertragen.

RBT
quelle
7

Folgendes habe ich in einem ähnlichen Beitrag geschrieben (zu diesem Thema). (Und nein, ich zitiere mich normalerweise nicht, aber das sind sehr gute Artikel.)

"Dieser Artikel ist hilfreich: IQueryable vs IEnumerable in LINQ-to-SQL .

In diesem Artikel heißt es: „Gemäß der MSDN-Dokumentation werden bei IQueryable getätigten Aufrufen stattdessen der interne Ausdrucksbaum erstellt. "Diese Methoden, die IQueryable (Of T) erweitern, führen keine direkte Abfrage durch. Stattdessen besteht ihre Funktionalität darin, ein Ausdrucksobjekt zu erstellen, bei dem es sich um einen Ausdrucksbaum handelt, der die kumulative Abfrage darstellt."

Ausdrucksbäume sind ein sehr wichtiges Konstrukt in C # und auf der .NET-Plattform. (Sie sind im Allgemeinen wichtig, aber C # macht sie sehr nützlich.) Um den Unterschied besser zu verstehen, empfehle ich, die Unterschiede zwischen Ausdrücken und Aussagen in der offiziellen C # 5.0-Spezifikation hier zu lesen . Für fortgeschrittene theoretische Konzepte, die in die Lambda-Rechnung verzweigen, ermöglichen Ausdrücke die Unterstützung von Methoden als erstklassige Objekte. Der Unterschied zwischen IQueryable und IEnumerable konzentriert sich auf diesen Punkt. IQueryable erstellt Ausdrucksbäume, IEnumerable jedoch nicht, zumindest nicht allgemein für diejenigen von uns, die nicht in den geheimen Labors von Microsoft arbeiten.

Hier ist ein weiterer sehr nützlicher Artikel, der die Unterschiede aus Push- / Pull-Perspektive beschreibt. (Mit "Push" vs. "Pull" beziehe ich mich auf die Richtung des Datenflusses. Reaktive Programmiertechniken für .NET und C #

Hier ist ein sehr guter Artikel, der die Unterschiede zwischen Anweisungs-Lambdas und Ausdrucks-Lambdas detailliert beschreibt und die Konzepte der Ausdrucksstress ausführlicher behandelt: Wiederholung von C # -Delegierten, Ausdrucksbäumen und Lambda-Anweisungen im Vergleich zu Lambda-Ausdrücken. . "

Devinbost
quelle
6

Wir verwenden IEnumerableund IQueryablebearbeiten die Daten, die aus der Datenbank abgerufen werden. IQueryableerbt von IEnumerable, IQueryableenthält also alle IEnumerableFunktionen. Der Hauptunterschied zwischen IQueryableund IEnumerablebesteht darin, dass IQueryabledie Abfrage mit Filtern ausgeführt wird, während IEnumerabledie Abfrage zuerst ausgeführt wird und dann die Daten basierend auf den Bedingungen gefiltert werden.

Eine detailliertere Unterscheidung finden Sie unten:

IEnumerable

  1. IEnumerableexistiert im System.CollectionsNamespace
  2. IEnumerable Führen Sie eine Auswahlabfrage auf der Serverseite aus, laden Sie Daten auf einer Clientseite in den Speicher und filtern Sie dann die Daten
  3. IEnumerable eignet sich zum Abfragen von Daten aus speicherinternen Sammlungen wie List, Array
  4. IEnumerable ist vorteilhaft für LINQ to Object- und LINQ to XML-Abfragen

IQueryable

  1. IQueryableexistiert im System.LinqNamespace
  2. IQueryable führt serverseitig eine 'Auswahlabfrage' mit allen Filtern aus
  3. IQueryable eignet sich zum Abfragen von Daten aus Sammlungen außerhalb des Speichers (z. B. Remote-Datenbank, Dienst)
  4. IQueryable ist vorteilhaft für LINQ to SQL-Abfragen

Wird IEnumerablealso im Allgemeinen für den Umgang mit In-Memory-Sammlungen verwendet, während IQueryablees im Allgemeinen zum Bearbeiten von Sammlungen verwendet wird.

VikrantMehr
quelle
2

IQueryable ist schneller als IEnumerable, wenn es sich um große Datenmengen aus der Datenbank handelt, da IQueryable nur die erforderlichen Daten aus der Datenbank abruft, wobei IEnumerable alle Daten unabhängig von der Notwendigkeit aus der Datenbank abruft

Arjun Bollam
quelle
0

ienumerable: Wenn wir uns mit Inprocess-Speicher befassen möchten, dh ohne Datenverbindung. iqueryable: Wann mit SQL Server, dh mit Datenverbindungs-Ilist: Operationen wie Objekt hinzufügen, Objekt löschen usw.

viswanath n. viswanath
quelle