LINQ:
Apakah lebih efisien menggunakan Single()
operator First()
kapan saja saya tahu pasti bahwa kueri akan mengembalikan satu catatan ?
Apakah ada perbedaan?
Saya tahu orang lain telah menulis mengapa Anda menggunakan satu atau yang lain, tapi saya pikir saya akan menggambarkan mengapa Anda TIDAK boleh menggunakan satu, ketika Anda maksud yang lain.
Catatan: Dalam kode saya, saya biasanya akan menggunakan FirstOrDefault()
dan SingleOrDefault()
tapi itu pertanyaan yang berbeda.
Ambil, misalnya, tabel yang menyimpan Customers
dalam berbagai bahasa menggunakan Kunci Komposit ( ID
, Lang
):
DBContext db = new DBContext();
Customer customer = db.Customers.Where( c=> c.ID == 5 ).First();
Kode di atas memperkenalkan kemungkinan kesalahan logika (sulit dilacak). Ini akan mengembalikan lebih dari satu catatan (dengan asumsi Anda memiliki catatan pelanggan dalam berbagai bahasa) tetapi itu akan selalu mengembalikan hanya yang pertama ... yang kadang-kadang bisa berfungsi ... tetapi tidak yang lain. Tidak dapat diprediksi.
Karena niat Anda adalah mengembalikan satu Customer
Penggunaan Single()
;
Berikut ini akan mengeluarkan pengecualian (yang Anda inginkan dalam kasus ini):
DBContext db = new DBContext();
Customer customer = db.Customers.Where( c=> c.ID == 5 ).Single();
Kemudian, Anda cukup memukul diri Anda sendiri dan berkata pada diri sendiri ... OOPS! Saya lupa bidang bahasa! Berikut ini adalah versi yang benar:
DBContext db = new DBContext();
Customer customer = db.Customers.Where( c=> c.ID == 5 && c.Lang == "en" ).Single();
First()
berguna dalam skenario berikut:
DBContext db = new DBContext();
NewsItem newsitem = db.NewsItems.OrderByDescending( n => n.AddedDate ).First();
Ini akan mengembalikan SATU objek, dan karena Anda menggunakan penyortiran, itu akan menjadi catatan terbaru yang dikembalikan.
Menggunakan Single()
ketika Anda merasa harus secara eksplisit selalu mengembalikan 1 catatan akan membantu Anda menghindari kesalahan logika.
customers.Where(predicate).Single()
customers.Single(predicate)
?Single akan mengeluarkan pengecualian jika menemukan lebih dari satu catatan yang cocok dengan kriteria. Pertama akan selalu memilih catatan pertama dari daftar. Jika kueri mengembalikan hanya 1 catatan, Anda dapat menggunakannya
First()
.Keduanya akan mengeluarkan
InvalidOperationException
pengecualian jika koleksinya kosong. Atau Anda bisa menggunakanSingleOrDefault()
. Ini tidak akan menghasilkan pengecualian jika daftar kosongsumber
Tunggal()
SingleOrDefault ()
Pertama()
FirstOrDefault ()
sumber
First
ketika 1 atau lebih elemen diharapkan , tidak hanya "lebih dari 1", danFirstOrDefault
dengan jumlah elemen apa pun.Ada perbedaan semantik dan halus antara kedua metode ini.
Gunakan
Single
untuk mengambil elemen pertama (dan hanya) dari urutan yang seharusnya mengandung satu elemen dan tidak lebih. Jika urutan memiliki lebih dari pada elemen permintaan AndaSingle
akan menyebabkan pengecualian dilempar karena Anda menunjukkan bahwa hanya ada satu elemen.Gunakan
First
untuk mengambil elemen pertama dari urutan yang dapat berisi sejumlah elemen. Jika urutan memiliki lebih dari pada elemen permintaan AndaFirst
tidak akan menyebabkan pengecualian untuk dilemparkan karena Anda menunjukkan bahwa Anda hanya perlu elemen pertama dalam urutan dan tidak peduli jika lebih ada.Jika urutan tidak mengandung elemen, kedua pemanggilan metode akan menyebabkan pengecualian karena kedua metode mengharapkan setidaknya satu elemen untuk hadir.
sumber
Jika Anda tidak secara khusus ingin pengecualian dilemparkan dalam acara tersebut bahwa ada lebih dari satu item, penggunaan
First()
.Keduanya efisien, ambil item pertama.
First()
sedikit lebih efisien karena tidak repot memeriksa untuk melihat apakah ada item kedua.Satu-satunya perbedaan adalah bahwa
Single()
mengharapkan hanya ada satu item dalam enumerasi untuk memulai, dan akan melempar pengecualian jika ada lebih dari satu. Anda menggunakan.Single()
jika Anda secara khusus ingin pengecualian yang dilemparkan dalam kasus ini.sumber
Jika saya ingat, Single () memeriksa apakah ada elemen lain setelah yang pertama (dan melempar pengecualian jika itu terjadi), sedangkan First () berhenti setelah mendapatkannya. Keduanya melempar pengecualian jika urutannya kosong.
Secara pribadi, saya selalu menggunakan First ().
sumber
Mengenai kinerja: Seorang rekan kerja dan saya sedang mendiskusikan kinerja Single vs First (atau SingleOrDefault vs FirstOrDefault), dan saya sedang memperdebatkan poin bahwa First (atau FirstOrDefault) akan lebih cepat dan meningkatkan kinerja (saya semua tentang membuat aplikasi kami lari lebih cepat).
Saya telah membaca beberapa posting tentang Stack Overflow yang memperdebatkan hal ini. Ada yang mengatakan ada keuntungan kinerja kecil menggunakan Pertama, bukan Tunggal. Ini karena Pertama hanya akan mengembalikan item pertama sementara Tunggal harus memindai semua hasil untuk memastikan tidak ada duplikat (yaitu: jika menemukan item di baris pertama tabel, masih akan memindai setiap baris lainnya untuk pastikan tidak ada nilai kedua yang cocok dengan kondisi yang kemudian akan menimbulkan kesalahan). Saya merasa seperti berada di tanah yang kokoh dengan "Pertama" lebih cepat dari "Lajang" jadi saya mulai membuktikannya dan mengakhiri perdebatan.
Saya menyiapkan tes di database saya dan menambahkan 1.000.000 baris ID UniqueIdentifier Asing UniqueIdentifier Info nvarchar (50) (diisi dengan deretan angka "0" hingga "999.999")
Saya memuat data dan menetapkan ID sebagai bidang kunci utama.
Menggunakan LinqPad, tujuan saya adalah untuk menunjukkan bahwa jika Anda mencari nilai pada 'Asing' atau 'Info' menggunakan Tunggal, itu akan jauh lebih buruk daripada menggunakan Pertama.
Saya tidak bisa menjelaskan hasil yang saya dapatkan. Di hampir setiap kasus, menggunakan Single atau SingleOrDefault sedikit lebih cepat. Ini tidak masuk akal bagi saya, tetapi saya ingin membagikannya.
Contoh: Saya menggunakan pertanyaan berikut:
Saya mencoba pertanyaan serupa pada bidang kunci 'Asing' yang tidak diindeks berpikir yang akan membuktikan bahwa Pertama lebih cepat, tetapi Tunggal selalu sedikit lebih cepat dalam pengujian saya.
sumber
Mereka berbeda. Keduanya menyatakan bahwa set hasil tidak kosong, tetapi tunggal juga menyatakan bahwa tidak ada lebih dari 1 hasil. Saya pribadi menggunakan Tunggal dalam kasus di mana saya hanya berharap ada 1 hasil hanya karena mendapatkan lebih dari 1 hasil kembali adalah kesalahan dan mungkin harus diperlakukan seperti itu.
sumber
Anda dapat mencoba contoh sederhana untuk mendapatkan perbedaan. Pengecualian akan dilakukan pada saluran 3;
sumber
Banyak orang yang saya kenal menggunakan FirstOrDefault (), tetapi saya cenderung menggunakan SingleOrDefault () lebih sering karena itu akan menjadi semacam ketidakkonsistenan data jika ada lebih dari satu. Ini berhubungan dengan LINQ-to-Objects.
sumber
Catatan dalam entitas Karyawan:
Employeeid = 1
: Hanya satu karyawan dengan ID iniFirstname = Robert
: Lebih dari satu karyawan dengan nama iniEmployeeid = 10
: Tidak ada karyawan dengan ID iniSekarang perlu untuk memahami apa
Single()
danFirst()
artinya secara rinci.Tunggal()
Tunggal () digunakan untuk mengembalikan catatan tunggal yang secara unik ada dalam tabel, sehingga permintaan di bawah ini akan mengembalikan Karyawan yang
employeed =1
karena kita hanya memiliki satu Karyawan yangEmployeed
1. Jika kita memiliki dua catatan untukEmployeeId = 1
maka itu menimbulkan kesalahan (lihat kesalahan di bawah dalam kueri kedua tempat kami menggunakan contoh untukFirstname
.Di atas akan mengembalikan satu catatan, yang memiliki 1
employeeId
Di atas akan melempar pengecualian karena catatan multilple ada di tabel untuk
FirstName='Robert'
. Pengecualiannya adalahIni akan, sekali lagi, melemparkan pengecualian karena tidak ada catatan untuk id = 10. Pengecualiannya adalah
Untuk
EmployeeId = 10
itu akan mengembalikan nol, tetapi seperti yang kita gunakanSingle()
akan menimbulkan kesalahan. Untuk menangani kesalahan nol, kita harus menggunakanSingleOrDefault()
.Pertama()
Pertama () mengembalikan dari beberapa catatan, catatan yang sesuai diurutkan dalam urutan menurut
birthdate
sehingga akan mengembalikan 'Robert' yang tertua.Di atas harus mengembalikan yang tertua, Robert sesuai DOB.
Di atas akan membuang pengecualian karena tidak ada catatan untuk id = 10 ada. Untuk menghindari pengecualian nol, kita harus menggunakan
FirstOrDefault()
daripadaFirst()
.Catatan: Kami hanya dapat menggunakan
First()
/Single()
ketika kami benar-benar yakin bahwa itu tidak dapat mengembalikan nilai nol.Dalam kedua fungsi gunakan SingleOrDefault () ATAU FirstOrDefault () yang akan menangani pengecualian nol, dalam kasus tidak ada catatan ditemukan itu akan mengembalikan nol.
sumber