Saya tahu beberapa perbedaan LINQ untuk Entitas dan LINQ untuk Objek yang mengimplementasikan pertama IQueryable
dan kedua IEnumerable
dan ruang lingkup pertanyaan saya berada di dalam EF 5.
Pertanyaan saya adalah apa perbedaan teknis dari ketiga metode tersebut? Saya melihat bahwa dalam banyak situasi semuanya bekerja. Saya juga melihat menggunakan kombinasi mereka suka .ToList().AsQueryable()
.
Apa arti metode-metode itu, tepatnya?
Apakah ada masalah kinerja atau sesuatu yang akan mengarah pada penggunaan satu di atas yang lain?
Mengapa seseorang menggunakan, misalnya,
.ToList().AsQueryable()
bukan.AsQueryable()
?
Jawaban:
Ada banyak yang bisa dikatakan tentang ini. Mari saya fokus pada
AsEnumerable
danAsQueryable
dan menyebutkanToList()
sepanjang jalan.Apa yang dilakukan metode ini?
AsEnumerable
danAsQueryable
cor atau mengkonversi keIEnumerable
atauIQueryable
, masing-masing. Saya katakan cast atau convert dengan alasan:Ketika objek sumber sudah mengimplementasikan antarmuka target, objek sumber itu sendiri dikembalikan tetapi dilemparkan ke antarmuka target. Dengan kata lain: tipe tidak berubah, tetapi tipe waktu kompilasi adalah.
Ketika objek sumber tidak mengimplementasikan antarmuka target, objek sumber dikonversi menjadi objek yang mengimplementasikan antarmuka target. Jadi tipe dan tipe waktu kompilasi diubah.
Izinkan saya menunjukkan ini dengan beberapa contoh. Saya punya metode kecil ini yang melaporkan tipe kompilasi-waktu dan tipe aktual objek ( seizin Jon Skeet ):
Mari kita coba Linq-to-sql
Table<T>
yang berubah-ubah , yang mengimplementasikanIQueryable
:Hasil:
Anda melihat bahwa kelas tabel itu sendiri selalu dikembalikan, tetapi perwakilannya berubah.
Sekarang objek yang mengimplementasikan
IEnumerable
, bukanIQueryable
:Hasil:
Itu ada.
AsQueryable()
telah mengonversi array menjadiEnumerableQuery
, yang "mewakiliIEnumerable<T>
koleksi sebagaiIQueryable<T>
sumber data." (MSDN).Apa gunanya?
AsEnumerable
sering digunakan untuk beralih dari setiapIQueryable
implementasi ke LINQ ke objek (L2O), sebagian besar karena mantan tidak mendukung fungsi yang dimiliki L2O. Untuk detail lebih lanjut lihat Apa efek AsEnumerable () pada Entitas LINQ? .Misalnya, dalam kueri Entity Framework kita hanya bisa menggunakan sejumlah metode terbatas. Jadi, jika, misalnya, kita perlu menggunakan salah satu metode kita sendiri dalam kueri, kita biasanya akan menulis sesuatu seperti
ToList
- yang mengubah suatuIEnumerable<T>
keList<T>
- sering juga digunakan untuk tujuan ini. Keuntungan menggunakanAsEnumerable
vs.ToList
adalahAsEnumerable
tidak menjalankan query.AsEnumerable
mempertahankan eksekusi yang ditangguhkan dan tidak membangun daftar perantara yang sering tidak berguna.Di sisi lain, ketika eksekusi yang diinginkan dari permintaan LINQ diinginkan,
ToList
bisa menjadi cara untuk melakukan itu.AsQueryable
dapat digunakan untuk membuat koleksi yang dapat diterima menerima ekspresi dalam pernyataan LINQ. Lihat di sini untuk detail lebih lanjut: Apakah saya benar-benar perlu menggunakan AsQueryable () pada koleksi? .Catatan tentang penyalahgunaan zat!
AsEnumerable
bekerja seperti narkoba. Ini perbaikan cepat, tetapi dengan biaya dan tidak mengatasi masalah yang mendasarinya.Dalam banyak jawaban Stack Overflow, saya melihat orang yang mendaftar
AsEnumerable
untuk memperbaiki masalah apa pun dengan metode yang tidak didukung dalam ekspresi LINQ. Tapi harganya tidak selalu jelas. Misalnya, jika Anda melakukan ini:... semuanya diterjemahkan dengan rapi ke dalam pernyataan SQL yang memfilter (
Where
) dan proyek (Select
). Artinya, baik panjang dan lebar, masing-masing, dari himpunan hasil SQL berkurang.Sekarang anggaplah pengguna hanya ingin melihat bagian tanggal dari
CreateDate
. Dalam Kerangka Entitas Anda akan dengan cepat menemukan bahwa ...... tidak didukung (pada saat penulisan). Ah, untungnya ada
AsEnumerable
perbaikannya:Tentu, ini berjalan, mungkin. Tapi itu menarik seluruh tabel ke dalam memori dan kemudian menerapkan filter dan proyeksi. Yah, kebanyakan orang cukup pintar untuk melakukan yang
Where
pertama:Namun tetap semua kolom diambil terlebih dahulu dan proyeksi dilakukan dalam memori.
Perbaikan sebenarnya adalah:
(Tapi itu hanya membutuhkan sedikit pengetahuan ...)
Apa yang tidak dilakukan metode ini?
Kembalikan kemampuan IQueryable
Sekarang peringatan penting. Saat kamu melakukan
Anda akan berakhir dengan objek sumber direpresentasikan sebagai
IQueryable
. (Karena kedua metode hanya menggunakan dan tidak mengkonversi).Tetapi ketika Anda melakukannya
apa hasilnya?
The
Select
menghasilkanWhereSelectEnumerableIterator
. Ini adalah kelas .Net internal yang mengimplementasikanIEnumerable
, bukanIQueryable
. Jadi konversi ke jenis lain telah terjadi dan selanjutnyaAsQueryable
tidak akan pernah dapat mengembalikan sumber aslinya lagi.Implikasi dari hal ini adalah bahwa menggunakan
AsQueryable
adalah bukan cara yang ajaib menyuntikkan penyedia permintaan dengan spesifik fitur menjadi enumerable. Misalkan Anda melakukannyaKondisi di mana tidak akan pernah diterjemahkan ke dalam SQL.
AsEnumerable()
diikuti oleh pernyataan LINQ yang secara definitif memutus koneksi dengan penyedia query framework framework.Saya sengaja menunjukkan contoh ini karena saya telah melihat pertanyaan di sini di mana orang-orang misalnya mencoba 'menyuntikkan'
Include
kemampuan ke dalam koleksi dengan meneleponAsQueryable
. Ini mengkompilasi dan menjalankan, tetapi tidak melakukan apa-apa karena objek yang mendasarinya tidak memilikiInclude
implementasi lagi.Menjalankan
Keduanya
AsQueryable
danAsEnumerable
tidak mengeksekusi (atau menyebutkan ) objek sumber. Mereka hanya mengubah tipe atau representasi mereka. Kedua antarmuka yang terlibat,IQueryable
danIEnumerable
, tidak lain adalah "enumerasi yang menunggu untuk terjadi". Mereka tidak dieksekusi sebelum mereka dipaksa untuk melakukannya, misalnya, seperti yang disebutkan di atas, dengan meneleponToList()
.Itu berarti bahwa mengeksekusi
IEnumerable
diperoleh dengan meneleponAsEnumerable
padaIQueryable
objek, akan mengeksekusi mendasariIQueryable
. Eksekusi selanjutnyaIEnumerable
akan kembali mengeksekusiIQueryable
. Yang mungkin sangat mahal.Implementasi khusus
Sejauh ini, ini hanya tentang
Queryable.AsQueryable
danEnumerable.AsEnumerable
metode penyuluhan. Tetapi tentu saja siapa pun dapat menulis metode instan atau metode ekstensi dengan nama (dan fungsi) yang sama.Bahkan, contoh umum dari
AsEnumerable
metode ekstensi spesifik adalahDataTableExtensions.AsEnumerable
.DataTable
tidak menerapkanIQueryable
atauIEnumerable
, jadi metode ekstensi reguler tidak berlaku.sumber
AsQueryable()
sering didasarkan pada kesalahpahaman. Tapi saya akan biarkan mendidih di belakang kepala saya untuk sementara waktu dan melihat apakah saya dapat menambahkan beberapa liputan tentang pertanyaan itu.ToList ()
AsEnumerable ()
Func<TSource, bool>
AsQueryable ()
Expression<Func<TSource, bool>>
AsQueryable()
biasanya bekerja jauh lebih cepat daripadaAsEnumerable()
yang menghasilkan T-SQL pada awalnya, yang mencakup semua kondisi Anda di Linq Anda.sumber
ToList () akan menjadi segalanya dalam memori dan kemudian Anda akan mengerjakannya. jadi, ToList (). di mana (terapkan beberapa filter) dijalankan secara lokal. AsQueryable () akan menjalankan semuanya dari jarak jauh yaitu filter di atasnya dikirim ke database untuk diterapkan. Queryable tidak melakukan apa pun hingga Anda menjalankannya. ToList, namun dieksekusi segera.
Juga, lihat jawaban ini Mengapa menggunakan AsQueryable () bukan List ()? .
EDIT: Juga, dalam kasus Anda setelah Anda melakukan ToList () maka setiap operasi selanjutnya adalah lokal termasuk AsQueryable (). Anda tidak dapat beralih ke jarak jauh setelah Anda mulai mengeksekusi secara lokal. Semoga ini membuatnya sedikit lebih jelas.
sumber
Mengalami kinerja buruk pada kode di bawah ini.
Diperbaiki dengan
Untuk IQueryable, tetap di IQueryable bila memungkinkan, cobalah untuk tidak digunakan seperti IEnumerable.
Perbarui . Lebih lanjut dapat disederhanakan dalam satu ungkapan, terima kasih Gert Arnold .
sumber