Qual è la differenza tra IQueryable<T>
e IEnumerable<T>
?
Vedi anche Qual è la differenza tra IQueryable e IEnumerable che si sovrappone a questa domanda.
Qual è la differenza tra IQueryable<T>
e IEnumerable<T>
?
Vedi anche Qual è la differenza tra IQueryable e IEnumerable che si sovrappone a questa domanda.
Risposte:
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 IQueryable
viene restituito rispettivamente un risultato di query o un altro .
AsQueryable()
eseguirà il cast di un enumerabile in un oggetto interrogabile e lo restituirà se implementa l' IQueryable
interfaccia, altrimenti lo avvolge in a ConstantExpression
, a cui fa riferimento un EnumerableQuery
oggetto restituito .
La differenza principale è che gli operatori LINQ per IQueryable<T>
prendere Expression
oggetti 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.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:
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' IQueryable
interfaccia eredita da IEnumerable
, quindi tutto ciò che IEnumerable
può fare, IQueryable
può anche fare.
Ci sono molte differenze, ma discutiamo dell'unica grande differenza che fa la differenza più grande. IEnumerable
l'interfaccia è utile quando la raccolta viene caricata utilizzando LINQ
o Entity framework e si desidera applicare il filtro sulla raccolta.
Considera il seguente codice semplice che utilizza IEnumerable
con il framework di entità. Sta usando un Where
filtro 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 IEnumerable
codice. In altre parole, tutti i dati vengono recuperati dal database e poi al cliente le sue scansioni e ottiene il record con EmpId
è 2
.
Ma ora vedere il codice di seguito abbiamo cambiato IEnumerable
a 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>();
Quindi la differenza tra IQueryable
e IEnumerable
riguarda 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.
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
Nella vita reale, se si utilizza un ORM come LINQ-to-SQL
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.
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 Employee
tabella nel database. Ho aggiunto un elemento ADO.NET Entity Data Model nell'applicazione console che punta alla Employee
tabella 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:
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:
SELECT [Extent1].[Salary] AS [Salary]
FROM [dbo].[Employee] AS [Extent1]
Ora vengono IEnumerable
portati tutti i 5 record presenti nella Salary
tabella 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.
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. ".
Utilizziamo IEnumerable
e IQueryable
manipoliamo i dati recuperati dal database. IQueryable
eredita da IEnumerable
, quindi IQueryable
contiene tutte le IEnumerable
funzionalità. La differenza principale tra IQueryable
e IEnumerable
è che IQueryable
esegue la query con i filtri mentre IEnumerable
esegue prima la query e quindi filtra i dati in base alle condizioni.
Trova la differenziazione più dettagliata di seguito:
IEnumerable
IEnumerable
esiste nello System.Collections
spazio dei nomiIEnumerable
eseguire una query di selezione sul lato server, caricare i dati in memoria sul lato client e quindi filtrare i datiIEnumerable
è adatto per l'interrogazione di dati da raccolte in memoria come List, ArrayIEnumerable
è utile per le query LINQ to Object e LINQ to XMLIQueryable
IQueryable
esiste nello System.Linq
spazio dei nomiIQueryable
esegue una "query di selezione" sul lato server con tutti i filtriIQueryable
è adatto per l'interrogazione di dati da raccolte di memoria insufficiente (come database remoto, servizio)IQueryable
è utile per le query LINQ to SQLQuindi IEnumerable
viene generalmente utilizzato per gestire la raccolta in memoria, mentre IQueryable
viene generalmente utilizzato per manipolare le raccolte.
Sia IEnumerable che IQueryable vengono utilizzati per contenere la raccolta di dati ed eseguire un'operazione di manipolazione dei dati, ad esempio il filtro sulla raccolta di dati. Qui puoi trovare il miglior confronto delle differenze con l'esempio. http://www.gurujipoint.com/2017/05/difference-between-ienumerable-and.html
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
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.