Kode Linq untuk memilih satu item


105

Saya menemukan diri saya menulis banyak kode seperti ini untuk memilih satu item yang cocok

var item = (from x in Items where x.Id == 123 select x).First();

Apakah ada cara yang lebih bersih untuk melakukannya atau apakah ini sesingkat yang akan saya dapatkan?

EDIT: Seharusnya mengatakan "Cara bersih menggunakan sintaks linq". Saya sudah mengetahui sintaks lambda dan mulai terlihat seperti ini sebenarnya satu-satunya cara. Saya memang mendapatkan beberapa info berguna, jadi terima kasih kepada semua orang yang menjawab.


5
Secara pribadi saya menghindari Single()dan SingleOrDefault()JIKA saya tahu datanya sudah unik (misalnya dari database yang memiliki kendala itu, dll), karena Single()memaksanya untuk memindai sisa daftar untuk menemukan kemungkinan duplikat, tapi itu saya. Jika Anda perlu menegakkan keunikan Anda saat ini, gunakan Single()keluarga, jika tidak, gunakan First()keluarga.
James Michael Hare

Jawaban:


176

Tergantung seberapa Anda menyukai sintaks kueri linq, Anda dapat menggunakan metode ekstensi secara langsung seperti:

var item = Items.First(i => i.Id == 123);

Dan jika Anda tidak ingin memunculkan kesalahan jika daftarnya kosong, gunakan FirstOrDefaultyang mengembalikan nilai default untuk tipe elemen ( nulluntuk tipe referensi):

var item = Items.FirstOrDefault(i => i.Id == 123);

if (item != null)
{
    // found it
}

Single()dan SingleOrDefault()juga dapat digunakan, tetapi jika Anda membaca dari database atau sesuatu yang sudah menjamin keunikan, saya tidak akan repot-repot karena harus memindai daftar untuk melihat apakah ada duplikat dan lemparan. First()dan FirstOrDefault()berhenti di pertandingan pertama, jadi mereka lebih efisien.

Dari keluarga First()dan Single(), inilah tempat mereka melempar:

  • First() - melempar jika kosong / tidak ditemukan, tidak melempar jika duplikat
  • FirstOrDefault() - mengembalikan default jika kosong / tidak ditemukan, tidak membuang jika duplikat
  • Single() - melempar jika kosong / tidak ditemukan, melempar jika ada duplikat
  • SingleOrDefault() - mengembalikan default jika kosong / tidak ditemukan, melempar jika ada duplikat

1
Saya pikir Anda kehilangan dua tanda yang sama di sana. Seharusnyai.Id == 123
davehale23

18

FirstOrDefault atau SingleOrDefault mungkin berguna, bergantung pada skenario Anda, dan apakah Anda ingin menangani jika tidak ada atau lebih dari satu kecocokan:

FirstOrDefault: Mengembalikan elemen pertama dari sebuah urutan, atau nilai default jika tidak ada elemen yang ditemukan.

SingleOrDefault: Mengembalikan satu-satunya elemen urutan, atau nilai default jika urutan kosong; metode ini melontarkan pengecualian jika ada lebih dari satu elemen dalam urutan

Saya tidak tahu bagaimana ini bekerja dalam kueri 'dari' linq tetapi dalam sintaks lambda terlihat seperti ini:

var item1 = Items.FirstOrDefault(x => x.Id == 123);
var item2 = Items.SingleOrDefault(x => x.Id == 123);

mana yang paling efisien dalam hal waktu DB? Jika saya memiliki varchar, saya menginginkan pencocokan yang tepat tetapi mungkin tidak ada?
Piotr Kula

2
Jawaban yang diterima membahas ini secara penuh, tetapi pada dasarnya FirstOrDefault berhenti segera setelah menemukan kecocokan, tetapi SingleOrDefault harus memeriksa seluruh daftar untuk memastikan tepat ada satu kecocokan.
mulai

12

Ini adalah metode yang disukai:

var item = Items.SingleOrDefault(x => x.Id == 123);

Atau

var item = Items.Single(x => x.Id == 123);

Terima kasih - jadi dalam situasi ini tidak ada notasi LINQ dan saya perlu menggunakan lambda?
Mikey Hogarth

Cukup bagus. Saya belum banyak menggunakan LINQ, jadi saya bahkan tidak yakin saya mengetahui metode ini.
wageoghe

1
Metode tunggal memeriksa bahwa nilai kembaliannya unik. Jadi, jika koleksi Anda banyak, bisa memakan waktu lama. Metode pertama hanya mengembalikan elemen pertama yang cocok dengan predikatnya.
meziantou

Jawaban @wageoghe James tidak menggunakan linq - metode Single dan SingleOrDefault adalah bagian dari implementasi IEnumerable.
Mikey Hogarth

12

Hanya untuk membuat hidup seseorang lebih mudah, kueri LINQ dengan ekspresi lambda

(from x in Items where x.Id == 123 select x).FirstOrDefault();

tidak menghasilkan kueri SQL dengan a select top (1)di dalamnya.


9

Itu lebih baik diringkas menjadi ini.

var item = Items.First(x => x.Id == 123);

Permintaan Anda saat ini sedang mengumpulkan semua hasil (dan mungkin ada lebih dari satu) dalam enumerable dan kemudian mengambil yang pertama dari yang ditetapkan, melakukan lebih banyak pekerjaan dari yang diperlukan.

Single / SingleOrDefault bermanfaat, tetapi hanya jika Anda ingin mengulangi seluruh koleksi dan memverifikasi bahwa kecocokan itu unik selain memilih kecocokan itu. First / FirstOrDefault hanya akan mengambil pertandingan pertama dan pergi, terlepas dari berapa banyak duplikat yang sebenarnya ada.


4

Anda dapat menggunakan sintaks metode ekstensi:

var item = Items.Select(x => x.Id == 123).FirstOrDefault();

Selain itu, saya tidak yakin seberapa ringkas Anda bisa mendapatkan, tanpa mungkin menulis metode ekstensi khusus "Pertama" dan "FirstOrDefault" Anda sendiri.


Saya tidak berpikir ini adalah perilaku yang dimaksudkan. Instruksi Select ini mengembalikan (sebenarnya tidak, tetapi memilih untuk dikembalikan) kumpulan bool, satu untuk setiap elemen Item, yang pertama dikembalikan sebagai item, yang menjadi sekadar bool. Gunakan solusi Chris Hannon
Leonardo Daga

Mungkin yang Anda maksud Wheresebagai lawan Select, yang telah dinyatakan, tetapi jawaban ini salah. Pilih di c # mengubah hasil ke IEnumerable <bool>, jadi Anda mendapatkan a booluntuk item pertamax.Id == 123
bradlis7

2

Saya akan memberi tahu Anda apa yang berhasil untuk saya:

int id = int.Parse(insertItem.OwnerTableView.DataKeyValues[insertItem.ItemIndex]["id_usuario"].ToString());

var query = user.First(x => x.id_usuario == id);
tbUsername.Text = query.username;
tbEmail.Text = query.email;
tbPassword.Text = query.password;

ID saya adalah baris yang ingin saya kueri, dalam hal ini saya mendapatkannya dari radGrid, lalu saya menggunakannya untuk kueri, tetapi kueri ini mengembalikan satu baris, lalu Anda dapat menetapkan nilai yang Anda dapatkan dari kueri ke kotak teks, atau apa pun , Saya harus menetapkannya ke kotak teks.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.