Qual è la differenza tra IQueryable <T> e IEnumerable <T>?


Risposte:


258

Prima di tutto, estende l' interfaccia, quindi tutto ciò che puoi fare con un "semplice" , puoi anche fare con un .IQueryable<T> IEnumerable<T>IEnumerable<T>IQueryable<T>

IEnumerable<T>appena ha un GetEnumerator()metodo che restituisce un Enumerator<T>per il quale è possibile chiamare il suo MoveNext()metodo per scorrere una sequenza di T .

Ciò IQueryable<T>che IEnumerable<T> non ha in particolare due proprietà, una che punta a un provider di query (ad esempio un provider LINQ to SQL) e un'altra che punta a un'espressione di query che rappresenta l' IQueryable<T>oggetto come un albero di sintassi astratto attraversabile da runtime che può essere compreso dal provider di query specificato (per la maggior parte, non è possibile fornire un'espressione LINQ to SQL a un provider LINQ to Entities senza che venga generata un'eccezione).

L'espressione può essere semplicemente un'espressione costante dell'oggetto stesso o un albero più complesso di un insieme composto di operatori e operandi di query. I metodi IQueryProvider.Execute()o il provider di query IQueryProvider.CreateQuery()vengono chiamati con un'espressione passata ad esso, quindi IQueryableviene restituito rispettivamente un risultato di query o un altro .


8
Ci sono dei vantaggi nell'usare AsQueryable?
Giordania,

6
L'unico vantaggio è la comodità. AsQueryable()eseguirà il cast di un enumerabile in un oggetto interrogabile e lo restituirà se implementa l' IQueryableinterfaccia, altrimenti lo avvolge in a ConstantExpression, a cui fa riferimento un EnumerableQueryoggetto restituito .
Mark Cidade,


1
Vale la pena leggere questo articolo
JenonD il

Il link @JenonD è morto, ecco la macchina del ritorno: web.archive.org/web/20160904162931/http://www.dotnet-tricks.com/…
majjam

201

La differenza principale è che gli operatori LINQ per IQueryable<T>prendere Expressionoggetti invece di delegati, il che significa che la logica di query personalizzata che riceve, ad esempio un predicato o un selettore di valori, ha la forma di un albero di espressioni anziché di un delegato a un metodo.

  • IEnumerable<T> è ottimo per lavorare con sequenze ripetute in memoria, ma
  • IQueryable<T> consente di esaurire la memoria, ad esempio un'origine dati remota, ad esempio un database o un servizio Web.

Esecuzione della query:

  • Laddove l'esecuzione di una query verrà eseguita "in elaborazione" , in genere è necessario solo il codice (come codice) per eseguire ciascuna parte della query.

  • Laddove l'esecuzione verrà eseguita fuori processo , la logica della query deve essere rappresentata in dati in modo tale che il provider LINQ possa convertirla nel modulo appropriato per l'esecuzione di memoria insufficiente, sia che si tratti di una query LDAP, SQL o altro.

Di più in:

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


14
Mi piace la menzione di operazioni di memoria insufficiente. Chiarisce una reale differenza pratica nell'uso.
Ishmael Smyrnow,

2
Invece di prendere i delegati come parametri come il metodo IEnumerable <T> Where, IQueryable <T> prenderà i parametri Expression <TDelegate>. Non stiamo passando codice in IQueryable <T>, stiamo passando alberi di espressioni (codice come dati) che il provider LINQ può analizzare. C # 3.0 e LINQ
Lu55,

qualcosa è collegato al tuo link immagine, non viene visualizzato nel corpo della posta per qualche motivo codeproject.com/KB/cs/646361/WhatHowWhere.jpg
jbooker

@joey Eppure, vedo bene l'immagine in questa risposta: i.stack.imgur.com/2DAqv.jpg
VonC

190

Questo è un bel video su YouTube che dimostra come queste interfacce differiscono, vale la pena guardarle.

Di seguito una lunga risposta descrittiva per questo.

Il primo punto importante da ricordare è l' IQueryableinterfaccia eredita da IEnumerable, quindi tutto ciò che IEnumerablepuò fare, IQueryablepuò anche fare.

inserisci qui la descrizione dell'immagine

Ci sono molte differenze, ma discutiamo dell'unica grande differenza che fa la differenza più grande. IEnumerablel'interfaccia è utile quando la raccolta viene caricata utilizzando LINQo Entity framework e si desidera applicare il filtro sulla raccolta.

Considera il seguente codice semplice che utilizza IEnumerablecon il framework di entità. Sta usando un Wherefiltro per ottenere i record di chi EmpIdè 2.

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

Questo dove il filtro viene eseguito sul lato client in cui si trova il IEnumerablecodice. In altre parole, tutti i dati vengono recuperati dal database e poi al cliente le sue scansioni e ottiene il record con EmpIdè 2.

inserisci qui la descrizione dell'immagine

Ma ora vedere il codice di seguito abbiamo cambiato IEnumerablea IQueryable. Crea una query SQL sul lato server e solo i dati necessari vengono inviati al lato client.

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

inserisci qui la descrizione dell'immagine

Quindi la differenza tra IQueryablee IEnumerableriguarda il punto in cui viene eseguita la logica del filtro. Uno viene eseguito sul lato client e l'altro viene eseguito sul database.

Pertanto, se si lavora solo con la raccolta di dati in memoria IEnumerableè una buona scelta, ma se si desidera eseguire una query sulla raccolta di dati collegata al database, IQueryable è una scelta migliore in quanto riduce il traffico di rete e utilizza la potenza del linguaggio SQL.


Ciao, grazie mille per la meravigliosa spiegazione. Capisco perché IQueryable è la scelta migliore per i dati "memoria insufficiente", ma faccio fatica a capire perché IEnumerable è migliore per i dati "in memoria"? Penso ancora che sia meglio ottenere dati filtrati piuttosto che ottenere dati e applicare il filtro.
Imad,

quando è "in memoria" non ha molta importanza. i dati sono già in memoria, a che ora esatta vengono filtrati non importa.
Roni Axelrad,

@Imad Ad esempio, la proiezione dei dati mediante la conversione dell'entità DateTimeOffset in DateTime non può essere eseguita in modo fattibile utilizzando IQueryable o EntityFunctions. Il modo migliore è di AsEnumerable () l'oggetto entità, quindi Select () in un viewmodel che contiene DateTime. Questo processo utilizza funzioni in memoria.
Jeff,

57

IEnumerable: IEnumerable è il più adatto per lavorare con raccolte in memoria (o query locali). IEnumerable non si sposta tra gli elementi, è solo la raccolta diretta.

IQueryable: IQueryable è la soluzione migliore per l'origine dati remota, come un database o un servizio Web (o query remote). IQueryable è una funzionalità molto potente che consente una varietà di scenari di esecuzione differita interessanti (come il paging e le query basate sulla composizione).

Quindi, quando devi semplicemente scorrere la raccolta in memoria, usa IEnumerable, se hai bisogno di manipolare la raccolta come Dataset e altre origini dati, usa IQueryable


3
IEnumerable non utilizza l'esecuzione differita?
Ian Warburton,

3
L'esecuzione differita è disponibile sia in IEnumerable che IQueryable. Ulteriori informazioni interessanti sono disponibili qui: stackoverflow.com/questions/2876616/…
Ignacio Hagopian

18

In altre parole, un'altra grande differenza è che IEnumerable esegue la query di selezione sul lato server, carica i dati in memoria sul lato client e quindi filtra i dati mentre IQueryable esegue la query di selezione sul lato server con tutti i filtri.


17

Nella vita reale, se si utilizza un ORM come LINQ-to-SQL

  • Se si crea un IQueryable, la query può essere convertita in sql ed eseguita sul server di database
  • Se si crea un IEnumerable, tutte le righe verranno rimosse in memoria come oggetti prima di eseguire la query.

In entrambi i casi se non si chiama una ToList()o ToArray()allora la query verrà eseguita ogni volta che viene utilizzata, quindi, per esempio, si ha una IQueryable<T>e si riempiono 4 caselle di elenco da essa, quindi la query verrà eseguita sul database 4 volte.

Anche se estendi la tua richiesta:

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

Quindi con un IQueryable l'SQL generato conterrà "dove name =" a ", ma con un IEnumerable molti più ruoli verranno ritirati dal database, quindi il controllo x.name =" a "verrà eseguito da .NET.


10

IEnumerable si riferisce a una raccolta ma IQueryable è solo una query e verrà generata all'interno di un albero delle espressioni. Eseguiremo questa query per ottenere dati dal database.


8

Di seguito un piccolo test potrebbe aiutarti a capire un aspetto della differenza tra IQueryable<T>e IEnumerable<T>. Ho riprodotto questa risposta da questo post in cui stavo cercando di aggiungere correzioni al post di qualcun altro

Ho creato la seguente struttura nel DB (script DDL):

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

Ecco lo script di inserimento record (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

Ora, il mio obiettivo era semplicemente ottenere i primi 2 record dalla Employeetabella nel database. Ho aggiunto un elemento ADO.NET Entity Data Model nell'applicazione console che punta alla Employeetabella nel mio database e ho iniziato a scrivere query LINQ.

Codice per percorso 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);
    }
}

Quando ho iniziato a eseguire questo programma, avevo anche avviato una sessione di SQL Query profiler sulla mia istanza di SQL Server ed ecco il riepilogo dell'esecuzione:

  1. Numero totale di query attivate: 1
  2. Testo della query: SELECT TOP (2) [c].[Salary] AS [Salary] FROM [dbo].[Employee] AS [c]

È solo che IQueryableè abbastanza intelligente da applicare la Top (2)clausola sul lato server database stesso, quindi porta solo 2 su 5 record via cavo. Non è necessario alcun ulteriore filtro in memoria sul lato computer client.

Codice per il percorso 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);
    }
}

Riepilogo dell'esecuzione in questo caso:

  1. Numero totale di query attivate: 1
  2. Testo della query acquisito nel profiler SQL: SELECT [Extent1].[Salary] AS [Salary] FROM [dbo].[Employee] AS [Extent1]

Ora vengono IEnumerableportati tutti i 5 record presenti nella Salarytabella e quindi eseguito un filtro in memoria sul computer client per ottenere i primi 2 record. Quindi più dati (3 record aggiuntivi in ​​questo caso) sono stati trasferiti sul cavo inutilmente.


7

Ecco cosa ho scritto su un post simile (su questo argomento). (E no, di solito non cito me stesso, ma questi sono ottimi articoli.)

"Questo articolo è utile: IQueryable vs IEnumerable in LINQ-to-SQL .

Citando quell'articolo, 'Secondo la documentazione MSDN, le chiamate fatte su IQueryable funzionano invece costruendo l'albero delle espressioni interne. "Questi metodi che estendono IQueryable (Of T) non eseguono direttamente alcuna query. Invece, la loro funzionalità è quella di costruire un oggetto Expression, che è un albero di espressioni che rappresenta la query cumulativa." '

Gli alberi delle espressioni sono un costrutto molto importante in C # e sulla piattaforma .NET. (Sono importanti in generale, ma C # li rende molto utili.) Per comprendere meglio la differenza, raccomando di leggere qui le differenze tra espressioni e dichiarazioni nella specifica C # 5.0 ufficiale. Per concetti teorici avanzati che si ramificano nel calcolo lambda, le espressioni consentono il supporto di metodi come oggetti di prima classe. La differenza tra IQueryable e IEnumerable è centrata attorno a questo punto. IQueryable crea alberi delle espressioni mentre IEnumerable non lo fa, almeno in termini generali per quelli di noi che non lavorano nei laboratori segreti di Microsoft.

Ecco un altro articolo molto utile che dettaglia le differenze da una prospettiva push vs. pull. (Per "push" vs. "pull", mi riferisco alla direzione del flusso di dati. Tecniche di programmazione reattiva per .NET e C #

Ecco un ottimo articolo che descrive in dettaglio le differenze tra l'affermazione lambda e l'espressione lambda e discute in modo più approfondito i concetti di espressione tress: Rivisitare delegati C #, alberi di espressioni e dichiarazioni lambda rispetto a espressioni lambda. ".


6

Utilizziamo IEnumerablee IQueryablemanipoliamo i dati recuperati dal database. IQueryableeredita da IEnumerable, quindi IQueryablecontiene tutte le IEnumerablefunzionalità. La differenza principale tra IQueryablee IEnumerableè che IQueryableesegue la query con i filtri mentre IEnumerableesegue prima la query e quindi filtra i dati in base alle condizioni.

Trova la differenziazione più dettagliata di seguito:

IEnumerable

  1. IEnumerableesiste nello System.Collectionsspazio dei nomi
  2. IEnumerable eseguire una query di selezione sul lato server, caricare i dati in memoria sul lato client e quindi filtrare i dati
  3. IEnumerable è adatto per l'interrogazione di dati da raccolte in memoria come List, Array
  4. IEnumerable è utile per le query LINQ to Object e LINQ to XML

IQueryable

  1. IQueryableesiste nello System.Linqspazio dei nomi
  2. IQueryable esegue una "query di selezione" sul lato server con tutti i filtri
  3. IQueryable è adatto per l'interrogazione di dati da raccolte di memoria insufficiente (come database remoto, servizio)
  4. IQueryable è utile per le query LINQ to SQL

Quindi IEnumerableviene generalmente utilizzato per gestire la raccolta in memoria, mentre IQueryableviene generalmente utilizzato per manipolare le raccolte.



2

IQueryable è più veloce di IEnumerable se abbiamo a che fare con enormi quantità di dati dal database perché, IQueryable ottiene solo i dati richiesti dal database dove IEnumerable ottiene tutti i dati indipendentemente dalla necessità dal database


0

ienumerable: quando vogliamo gestire la memoria di processo, ovvero senza connessione dati iqueryable: quando gestire il server sql, ovvero con ilist di connessione dati: operazioni come aggiungere oggetto, eliminare oggetto ecc.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.