Apa perbedaan antara IQueryable <T> dan IEnumerable <T>?

Jawaban:

258

Pertama-tama, meluas yang antarmuka, sehingga apa pun yang Anda bisa lakukan dengan "polos" , Anda juga dapat melakukan dengan .IQueryable<T> IEnumerable<T>IEnumerable<T>IQueryable<T>

IEnumerable<T>hanya memiliki GetEnumerator()metode yang mengembalikan sebuah Enumerator<T>yang Anda dapat menghubungi yang MoveNext()metode untuk iterate melalui urutan T .

Apa IQueryable<T>yang IEnumerable<T> tidak memiliki itu adalah dua properti khususnya — yang menunjuk ke penyedia kueri (mis., Penyedia LINQ ke SQL) dan yang lain menunjuk ke ekspresi kueri yang mewakili IQueryable<T>objek sebagai pohon sintaks abstrak runtime-traversable yang bisa menjadi dipahami oleh penyedia kueri yang diberikan (sebagian besar, Anda tidak bisa memberikan ekspresi LINQ ke SQL ke penyedia LINQ ke Entitas tanpa pengecualian dilemparkan).

Ekspresi dapat berupa ekspresi konstan dari objek itu sendiri atau pohon yang lebih kompleks dari kumpulan operator dan operan kueri yang terdiri. Penyedia IQueryProvider.Execute()atau IQueryProvider.CreateQuery()metode kueri dipanggil dengan Ekspresi yang diteruskan ke sana, dan kemudian salah satu hasil kueri atau lainnya IQueryabledikembalikan, masing-masing.

Mark Cidade
sumber
8
Apakah ada manfaat menggunakan AsQueryable?
Jordan
6
Satu-satunya manfaat adalah kenyamanan. AsQueryable()hanya akan melemparkan enumerable ke queryable dan mengembalikannya jika itu mengimplementasikan IQueryableantarmuka, jika tidak membungkusnya dalam ConstantExpression, yang disebut dalam EnumerableQueryobjek yang dikembalikan .
Mark Cidade
3
Pertanyaan terkait: Klarifikasi IEnumerable <T> dan IQueryable <T>?
Christopher Stevenson
1
Layak membaca artikel
JenonD
Tautan @JenonD sudah mati, inilah waybackmachine: web.archive.org/web/20160904162931/http://www.dotnet-tricks.com/…
majjam
201

Perbedaan utama adalah bahwa operator LINQ untuk IQueryable<T>mengambil Expressionobjek alih-alih delegasi, yang berarti logika kueri kustom yang diterimanya, misalnya, predikat atau pemilih nilai, adalah dalam bentuk pohon ekspresi daripada delegasi ke metode.

  • IEnumerable<T> bagus untuk bekerja dengan urutan yang di-memori berulang, tetapi
  • IQueryable<T> memungkinkan kehabisan memori hal-hal seperti sumber data jarak jauh, seperti database atau layanan web.

Eksekusi kueri:

  • Di mana eksekusi permintaan akan dilakukan "dalam proses" , biasanya semua yang diperlukan adalah kode (sebagai kode) untuk mengeksekusi setiap bagian dari permintaan.

  • Di mana eksekusi akan dilakukan di luar proses , logika kueri harus diwakili dalam data sehingga penyedia LINQ dapat mengubahnya menjadi bentuk yang sesuai untuk eksekusi di luar memori - apakah itu permintaan LDAP, SQL atau apa pun.

Lebih banyak di:

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

VonC
sumber
14
Saya suka menyebutkan operasi di luar memori. Ini menjelaskan perbedaan praktis yang nyata dalam penggunaan.
Ismael Smyrnow
2
Alih-alih mengambil delegasi sebagai parameter seperti metode IEnumerable <T> Dimana, IQueryable <T> akan mengambil parameter Ekspresi <TDelegate>. Kami tidak meneruskan kode ke IQueryable <T>, kami meneruskan pohon ekspresi (kode sebagai data) untuk dianalisis oleh penyedia LINQ. C # 3.0 dan LINQ
Lu55
sesuatu yang dengan image link Anda, yang tidak render dalam tubuh posting untuk beberapa alasan codeproject.com/KB/cs/646361/WhatHowWhere.jpg
jbooker
@ Joey Namun, saya melihat gambar baik-baik saja dalam jawaban ini: i.stack.imgur.com/2DAqv.jpg
VonC
190

Ini adalah video yang bagus di youtube yang menunjukkan bagaimana antarmuka ini berbeda, layak tonton.

Di bawah ini pergi jawaban deskriptif panjang untuk itu.

Poin penting pertama yang harus diingat adalah IQueryableantarmuka diturunkan IEnumerable, jadi apa pun yang IEnumerablebisa dilakukan, IQueryablejuga bisa dilakukan.

masukkan deskripsi gambar di sini

Ada banyak perbedaan tetapi mari kita bahas tentang satu perbedaan besar yang membuat perbedaan terbesar. IEnumerableantarmuka berguna ketika koleksi Anda dimuat menggunakan LINQatau kerangka kerja Entity dan Anda ingin menerapkan filter pada koleksi.

Pertimbangkan kode sederhana di bawah ini yang digunakan IEnumerabledengan kerangka kerja entitas. Ini menggunakan Wherefilter untuk mendapatkan catatan yang EmpIdadalah 2.

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

Filter ini dijalankan di sisi klien tempat IEnumerablekode berada. Dengan kata lain semua data diambil dari database dan kemudian pada klien scan dan mendapat catatan dengan EmpIditu 2.

masukkan deskripsi gambar di sini

Tapi sekarang lihat di bawah kode yang kami telah berubah IEnumerableke IQueryable. Itu menciptakan SQL Query di sisi server dan hanya data yang diperlukan dikirim ke sisi klien.

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

masukkan deskripsi gambar di sini

Jadi perbedaan antara IQueryabledan IEnumerabletentang di mana filter logika dijalankan. Satu dieksekusi di sisi klien dan yang lain dijalankan pada database.

Jadi jika Anda hanya bekerja dengan pengumpulan data dalam memori IEnumerableadalah pilihan yang baik tetapi jika Anda ingin meminta pengumpulan data yang terhubung dengan database `IQueryable adalah pilihan yang lebih baik karena mengurangi lalu lintas jaringan dan menggunakan kekuatan bahasa SQL.

Shivprasad Koirala
sumber
Hai, terima kasih banyak untuk penjelasannya. Saya mengerti mengapa IQueryable adalah pilihan yang lebih baik untuk data "out-of-memory" tetapi saya berjuang untuk memahami mengapa IEnumerable lebih baik untuk data "in-memory"? Saya masih berpikir lebih baik mendapatkan data yang difilter daripada mendapatkan data dan menerapkan filter.
Imad
ketika "di-memori" itu tidak masalah. data sudah ada di memori, pada waktu yang tepat itu difilter tidak masalah.
Roni Axelrad
@Imad Misalnya, memproyeksikan data dengan mengubah entitas DateTimeOffset ke DateTime tidak mungkin dilakukan menggunakan IQueryable atau dengan EntityFunctions. Cara terbaik adalah dengan AsEnumerable () objek entitas, lalu Pilih () ke dalam viewmodel yang berisi DateTime. Proses ini menggunakan fungsi dalam memori.
Jeff
57

IEnumerable: IEnumerable paling cocok untuk bekerja dengan koleksi di-memori (atau permintaan lokal). IEnumerable tidak bergerak di antara item, itu hanya koleksi ke depan.

IQueryable: IQueryable paling cocok untuk sumber data jarak jauh, seperti basis data atau layanan web (atau permintaan jarak jauh). IQueryable adalah fitur yang sangat kuat yang memungkinkan berbagai skenario eksekusi yang ditangguhkan menarik (seperti permintaan halaman dan komposisi berdasarkan).

Jadi ketika Anda harus hanya mengulangi melalui koleksi di dalam memori, gunakan IEnumerable, jika Anda perlu melakukan manipulasi dengan koleksi seperti Dataset dan sumber data lainnya, gunakan IQueryable

Talha
sumber
3
Tidakkah IEnumerable menggunakan eksekusi yang ditangguhkan?
Ian Warburton
3
Eksekusi yang ditangguhkan tersedia dalam IEnumerable dan IQueryable. Info menarik lebih lanjut dapat ditemukan di sini: stackoverflow.com/questions/2876616/...
Ignacio Hagopian
18

Dengan kata sederhana, perbedaan utama lainnya adalah IEnumerable menjalankan query pilih di sisi server, memuat data di-memori di sisi klien dan kemudian menyaring data sementara IQueryable mengeksekusi query pilih di sisi server dengan semua filter.

DI
sumber
17

Dalam kehidupan nyata, jika Anda menggunakan ORM seperti LINQ-to-SQL

  • Jika Anda membuat IQueryable, maka kueri dapat dikonversi ke sql dan dijalankan di server database
  • Jika Anda membuat IEnumerable, maka semua baris akan ditarik ke dalam memori sebagai objek sebelum menjalankan kueri.

Dalam kedua kasus jika Anda tidak memanggil ToList()atau ToArray()kemudian permintaan akan dieksekusi setiap kali digunakan, jadi, katakanlah, Anda memiliki IQueryable<T>dan Anda mengisi 4 kotak daftar dari itu, maka permintaan akan dijalankan terhadap database 4 kali.

Juga jika Anda memperluas kueri Anda:

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

Kemudian dengan IQueryable SQL yang dihasilkan akan berisi "di mana nama =" a ", tetapi dengan IEnumerable banyak peran akan ditarik kembali dari database, maka pemeriksaan x.name =" a "akan dilakukan oleh .NET.

Ian Ringrose
sumber
10

IEnumerable merujuk pada koleksi tetapi IQueryable hanyalah sebuah kueri dan akan dihasilkan di dalam Pohon Ekspresi. Kami akan menjalankan kueri ini untuk mendapatkan data dari basis data.

seyed
sumber
8

Tes kecil yang disebutkan di bawah ini dapat membantu Anda memahami satu aspek perbedaan antara IQueryable<T>dan IEnumerable<T>. Saya telah mereproduksi jawaban ini dari pos ini di mana saya mencoba menambahkan koreksi ke pos orang lain

Saya membuat struktur berikut dalam DB (skrip DDL):

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

Berikut ini skrip penyisipan rekaman (skrip 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

Sekarang, tujuan saya adalah hanya mendapatkan 2 catatan teratas dari Employeetabel dalam database. Saya menambahkan item Model Data Entitas ADO.NET ke dalam aplikasi konsol saya yang menunjuk ke Employeetabel dalam database saya dan mulai menulis kueri LINQ.

Kode untuk rute 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);
    }
}

Ketika saya mulai menjalankan program ini, saya juga memulai sesi profiler SQL Query pada contoh SQL Server saya dan di sini adalah ringkasan dari eksekusi:

  1. Total jumlah pertanyaan yang dipecat: 1
  2. Teks kueri: SELECT TOP (2) [c].[Salary] AS [Salary] FROM [dbo].[Employee] AS [c]

Hanya itu saja IQueryable cukup pintar untuk menerapkan Top (2)klausa di sisi server database itu sendiri sehingga hanya membawa 2 dari 5 catatan melalui kabel. Penyaringan dalam memori lebih lanjut tidak diperlukan sama sekali di sisi komputer klien.

Kode untuk rute 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);
    }
}

Ringkasan eksekusi dalam hal ini:

  1. Total jumlah pertanyaan yang dipecat: 1
  2. Teks kueri yang ditangkap dalam profiler SQL: SELECT [Extent1].[Salary] AS [Salary] FROM [dbo].[Employee] AS [Extent1]

Sekarang masalahnya IEnumerabledibawa semua 5 catatan hadir dalam Salarytabel dan kemudian melakukan pemfilteran di-memori pada komputer klien untuk mendapatkan 2 catatan teratas. Jadi lebih banyak data (3 catatan tambahan dalam kasus ini) yang ditransfer melalui kabel tanpa perlu.

RBT
sumber
7

Inilah yang saya tulis pada posting serupa (pada topik ini). (Dan tidak, saya biasanya tidak mengutip diri saya sendiri, tetapi ini adalah artikel yang sangat bagus.)

"Artikel ini bermanfaat: IQueryable vs IEnumerable di LINQ-to-SQL .

Mengutip artikel itu, 'Sesuai dokumentasi MSDN, panggilan yang dibuat di IQueryable beroperasi dengan membangun pohon ekspresi internal sebagai gantinya. "Metode-metode ini yang memperluas IQueryable (Of T) tidak melakukan kueri langsung. Alih-alih, fungsinya adalah untuk membangun objek Ekspresi, yang merupakan pohon ekspresi yang mewakili permintaan kumulatif." '

Pohon ekspresi adalah konstruk yang sangat penting dalam C # dan pada platform .NET. (Mereka penting secara umum, tetapi C # membuatnya sangat berguna.) Untuk lebih memahami perbedaannya, saya sarankan membaca tentang perbedaan antara ekspresi dan pernyataan dalam spesifikasi resmi C # 5.0 di sini. Untuk konsep teoritis canggih yang bercabang ke dalam kalkulus lambda, ekspresi memungkinkan dukungan untuk metode sebagai objek kelas satu. Perbedaan antara IQueryable dan IEnumerable berpusat di sekitar titik ini. IQueryable membangun pohon ekspresi sedangkan IEnumerable tidak, setidaknya tidak secara umum untuk kita yang tidak bekerja di laboratorium rahasia Microsoft.

Berikut ini adalah artikel lain yang sangat berguna yang merinci perbedaan dari perspektif push vs pull. (Dengan "push" vs. "pull," saya mengacu pada arah aliran data. Teknik Pemrograman Reaktif untuk .NET dan C #

Berikut ini adalah artikel yang sangat bagus yang merinci perbedaan antara pernyataan lambdas dan ekspresi lambdas dan membahas konsep ekspresi tress secara lebih mendalam: Meninjau kembali delegasi C #, pohon ekspresi, dan pernyataan lambda vs ekspresi lambda. . "

devinbost
sumber
6

Kami menggunakan IEnumerabledan IQueryableuntuk memanipulasi data yang diambil dari basis data. IQueryablemewarisi dari IEnumerable, demikian IQueryablejuga mengandung semua IEnumerablefitur. Perbedaan utama antara IQueryabledan IEnumerableadalah yang IQueryablemengeksekusi kueri dengan filter sedangkan IEnumerablemengeksekusi kueri pertama dan kemudian menyaring data berdasarkan kondisi.

Temukan diferensiasi lebih rinci di bawah ini:

Tidak terhitung

  1. IEnumerableada di System.Collectionsnamespace
  2. IEnumerable menjalankan kueri pemilihan di sisi server, memuat data dalam memori pada sisi klien dan kemudian menyaring data
  3. IEnumerable cocok untuk menanyakan data dari koleksi dalam memori seperti Daftar, Array
  4. IEnumerable bermanfaat untuk LINQ to Object dan LINQ to query XML

IQueryable

  1. IQueryableada di System.Linqnamespace
  2. IQueryable mengeksekusi 'query pilih' di sisi server dengan semua filter
  3. IQueryable cocok untuk menanyakan data dari koleksi out-memory (seperti basis data jauh, layanan)
  4. IQueryable bermanfaat untuk permintaan LINQ to SQL

Jadi IEnumerableumumnya digunakan untuk berurusan dengan koleksi dalam memori, sedangkan, IQueryableumumnya digunakan untuk memanipulasi koleksi.

VikrantMore
sumber
2

IQueryable lebih cepat daripada IEnumerable jika kita berhadapan dengan sejumlah besar data dari database karena, IQueryable hanya mendapatkan data yang diperlukan dari database sedangkan IEnumerable mendapatkan semua data terlepas dari kebutuhan dari database

arjun bollam
sumber
0

ienumerable: ketika kita ingin berurusan dengan memori inprocess, yaitu tanpa koneksi data iqueryable: kapan harus berurusan dengan sql server, yaitu dengan koneksi data ilist: operasi seperti menambah objek, menghapus objek dll

Viswanath n
sumber