Kod Linq, aby wybrać jedną pozycję


105

Piszę dużo takiego kodu, aby wybrać jeden pasujący element

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

Czy jest na to czystszy sposób, czy jest to tak zwięzłe, jak zamierzam?

EDYCJA: Powinienem był powiedzieć „Czystszy sposób korzystania ze składni linq”. Byłem już świadomy składni lambda i zaczyna wyglądać, że to właściwie jedyny sposób. Dostałem jednak przydatne informacje, więc dziękuję wszystkim, którzy odpowiedzieli.


5
Osobiście unikam Single()i SingleOrDefault()JEŚLI wiem, że dane są już unikalne (na przykład z bazy danych, która ma to ograniczenie itp.), Ponieważ Single()zmusza ją do przeszukania reszty listy w celu znalezienia możliwego duplikatu, ale to ja. Jeśli w tym momencie musisz narzucić swoją wyjątkowość, użyj Single()rodziny, jeśli nie, użyj First()rodziny.
— James Michael Hare

Odpowiedzi:


176

W zależności od tego, jak bardzo podoba Ci się składnia zapytania linq, możesz użyć metod rozszerzających bezpośrednio, takich jak:

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

A jeśli nie chcesz zgłaszać błędu, jeśli lista jest pusta, użyj funkcji, FirstOrDefaultktóra zwraca domyślną wartość dla typu elementu ( nulldla typów referencyjnych):

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

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

Single()i SingleOrDefault()może być również używany, ale jeśli czytasz z bazy danych lub czegoś, co już gwarantuje wyjątkowość, nie przejmowałbym się, ponieważ musi skanować listę, aby sprawdzić, czy są jakieś duplikaty i wyrzuty. First()i FirstOrDefault()zatrzymają się na pierwszym meczu, dzięki czemu są bardziej wydajni.

Z rodziny First()i Single(), oto gdzie rzucają:

  • First() - wyrzuca, jeśli jest pusty / nie znaleziony, nie rzuca, jeśli jest zduplikowany
  • FirstOrDefault() - zwraca wartość domyślną, jeśli jest pusta / nie znaleziono, nie rzuca, jeśli jest zduplikowana
  • Single() - wyrzuca, jeśli jest pusty / nie znaleziono, wyrzuca, jeśli istnieje duplikat
  • SingleOrDefault() - zwraca wartość domyślną, jeśli jest pusta / nie znaleziono, zgłasza, jeśli istnieje duplikat

1
Myślę, że brakuje tam dwóch znaków równości. Powinno byći.Id == 123
— davehale23

18

FirstOrDefault lub SingleOrDefault mogą być przydatne, w zależności od scenariusza i tego, czy chcesz obsłużyć zero lub więcej dopasowań:

FirstOrDefault: zwraca pierwszy element sekwencji lub wartość domyślną, jeśli nie zostanie znaleziony żaden element.

SingleOrDefault: zwraca jedyny element sekwencji lub wartość domyślną, jeśli sekwencja jest pusta; ta metoda zgłasza wyjątek, jeśli w sekwencji jest więcej niż jeden element

Nie wiem, jak to działa w zapytaniu linq „from”, ale w składni lambda wygląda to tak:

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

który z nich jest najbardziej efektywny pod względem czasu DB? Gdybym miał varchar, chciałem dokładnego dopasowania, ale możliwe, że nie ma takiego?
— Piotr Kula

2
Zaakceptowana odpowiedź w pełni rozwiązuje ten problem, ale zasadniczo FirstOrDefault zatrzymuje się, gdy tylko znajdzie dopasowanie, ale SingleOrDefault musi zbadać całą listę, aby upewnić się, że istnieje dokładnie jedno dopasowanie.
— stuartd

12

Oto preferowane metody:

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

Lub

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

Dzięki - czy w tej sytuacji nie ma notacji linq i muszę używać lambd?
— Mikey Hogarth

To całkiem nieźle. Tak naprawdę nie korzystałem zbyt często z Linq, więc nie jestem pewien, czy byłem nawet świadomy tych metod.
— wageoghe

1
Metoda pojedyncza sprawdza, czy zwracana wartość jest unikalna. Więc jeśli twoja kolekcja jest duża, może to zająć dużo czasu. Pierwsza metoda po prostu zwraca pierwszy element, który pasuje do predykatu.
— meziantou

Odpowiedź @wageoghe Jamesa nie używa linq - metody Single i SingleOrDefault są częścią implementacji IEnumerable.
— Mikey Hogarth

12

Aby ułatwić komuś życie, zapytanie linq z wyrażeniem lambda

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

powoduje zapytanie SQL zawierające select top (1)w sobie.


9

Można to lepiej sprowadzić do tego.

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

Twoje zapytanie zbiera obecnie wszystkie wyniki (a może być więcej niż jeden) w ramach wyliczenia, a następnie pobiera pierwszy z tego zestawu, wykonując więcej pracy niż to konieczne.

Single / SingleOrDefault są warte zachodu, ale tylko wtedy, gdy chcesz wykonać iterację przez całą kolekcję i sprawdzić, czy dopasowanie jest unikalne, oprócz wybrania tego dopasowania. First / FirstOrDefault po prostu weźmie pierwsze dopasowanie i opuści, niezależnie od tego, ile faktycznie duplikatów istnieje.


4

Możesz użyć składni metody rozszerzenia:

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

Poza tym nie jestem pewien, o ile bardziej zwięźle można uzyskać bez pisania własnych wyspecjalizowanych metod rozszerzających „First” i „FirstOrDefault”.


Nie sądzę, żeby było to zamierzone zachowanie. Ta instrukcja Select zwraca (właściwie tego nie robi, ale wybiera do zwrotu) zbiór bool, po jednym dla każdego elementu Items, pierwszego z tego, co jest zwracane jako element, który staje się po prostu wartością logiczną. Skorzystaj z rozwiązania Chrisa Hannona
— Leonardo Dagi

Być może masz na myśli Wherew przeciwieństwie do tego Select, co już zostało powiedziane, ale ta odpowiedź jest nieprawidłowa. Wybierz w c # zmienia wyniki na IEnumerable <bool>, więc otrzymujesz booldla pierwszego elementux.Id == 123
— bradlis7

2

Powiem ci, co mi pomogło:

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;

Mój identyfikator to wiersz, który chcę zapytać, w tym przypadku otrzymałem go z radGrid, a następnie użyłem go do zapytania, ale to zapytanie zwraca wiersz, a następnie możesz przypisać wartości otrzymane z zapytania do pola tekstowego lub cokolwiek , Musiałem je przypisać do pola tekstowego.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.