Jaka jest różnica między IQueryable a IEnumerable

Odpowiedzi:

186

IEnumerable<T>reprezentuje kursor tylko do przodu T. .NET 3.5 dodał metody rozszerzające, które obejmowały LINQ standard query operatorspodobne Wherei First, z dowolnymi operatorami, które wymagają predykatów lub przyjmowania funkcji anonimowych Func<T>.

IQueryable<T>implementuje te same standardowe operatory zapytań LINQ, ale akceptuje Expression<Func<T>>dla predykatów i funkcji anonimowych. Expression<T>jest skompilowanym drzewem wyrażeń, zepsutą wersją metody (jeśli wolisz "w połowie skompilowaną"), która może zostać przeanalizowana przez dostawcę zapytania i odpowiednio użyta.

Na przykład:

IEnumerable<Person> people = GetEnumerablePeople();
Person person = people.Where(x => x.Age > 18).FirstOrDefault();

IQueryable<Person> people = GetQueryablePeople();
Person person = people.Where(x => x.Age > 18).FirstOrDefault();

W pierwszym bloku x => x.Age > 18znajduje się metoda anonimowa ( Func<Person, bool>), która może być wykonana jak każda inna metoda. Enumerable.Wherewykona metodę raz dla każdej osoby, yieldokreślając wartości, dla których metoda zwróciła true.

W drugim bloku x => x.Age > 18znajduje się drzewo wyrażenia ( Expression<Func<Person, bool>>), które można traktować jako „właściwość„ Wiek ”> 18”.

Pozwala to na istnienie rzeczy takich jak LINQ-to-SQL, ponieważ mogą analizować drzewo wyrażeń i konwertować je na równoważny kod SQL. A ponieważ dostawca nie musi wykonywać, dopóki nie IQueryablezostanie wyliczony (w końcu implementuje IEnumerable<T>), może łączyć wiele operatorów zapytań (w powyższym przykładzie Wherei FirstOrDefault), aby dokonywać mądrzejszych wyborów dotyczących sposobu wykonania całego zapytania względem danych bazowych źródło (jak używanie SELECT TOP 1w SQL).

Widzieć:

Richard Szalay
źródło
1
dość krótka odpowiedź
ashveli
83

W prawdziwym życiu, jeśli używasz ORM, takiego jak LINQ-to-SQL

  • Jeśli utworzysz IQueryablezapytanie, wówczas zapytanie może zostać przekonwertowane na sql i uruchomione na serwerze bazy danych
  • Jeśli utworzysz IEnumerable, wszystkie wiersze zostaną wciągnięte do pamięci jako obiekty przed uruchomieniem zapytania.

W obu przypadkach, jeśli nie wywołasz a ToList()lub ToArray()wtedy zapytanie zostanie wykonane za każdym razem, gdy zostanie użyte, więc powiedzmy, że masz IQueryablei wypełnisz z niego 4 listy, wówczas zapytanie zostanie uruchomione w bazie danych 4 razy.

Również jeśli rozszerzysz swoje zapytanie:

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

Następnie IQueryablewygenerowany kod SQL będzie zawierał where name = "a", ale przy IEnumerableznacznie większej liczbie ról zostanie wycofany z bazy danych, wtedy x.name = "a"sprawdzenie zostanie wykonane przez .NET.

Ian Ringrose
źródło
„zapytanie można przekonwertować na sql”: nie otrzymałem „może być”. Ponadto, jeśli mam IEnumerable i utworzę „złożony łańcuch”, to (oczywiście) w przeciwieństwie do IQueryable, nie zostanie on przetłumaczony na „zoptymalizowane” zapytanie SQL. Chcę tylko potwierdzić, co to znaczy, gdy powiesz „wszystkie wiersze zostaną wciągnięte do pamięci”. Powiedzmy, że mam dwie klauzule where, czy wszystkie krotki jednostek zostaną najpierw załadowane do pamięci, a następnie nastąpi normalne filtrowanie w pamięci?
Vaibhav
36

„Podstawowa różnica polega na tym, że metody rozszerzające zdefiniowane dla IQueryable pobierają obiekty Expression zamiast obiektów Func, co oznacza, że ​​otrzymywany delegat jest drzewem wyrażeń, a nie metodą do wywołania. IEnumerable doskonale nadaje się do pracy z kolekcjami w pamięci, ale IQueryable pozwala dla zdalnego źródła danych, takiego jak baza danych lub usługa internetowa ”

Źródło: tutaj

Gabe
źródło
19

IEnumerable IEnumerable najlepiej nadaje się do pracy z kolekcją w pamięci. IEnumerable nie przenosi się między elementami, jest to kolekcja tylko do przodu.

IQueryable IQueryable najlepiej nadaje się do zdalnego źródła danych, takiego jak baza danych lub usługa internetowa. IQueryable to bardzo potężna funkcja, która umożliwia wiele interesujących scenariuszy odroczonego wykonania (takich jak zapytania oparte na stronicowaniu i składzie).

Więc kiedy musisz po prostu przejść przez kolekcję w pamięci, użyj IEnumerable, jeśli musisz wykonać jakiekolwiek manipulacje z kolekcją, taką jak Dataset i inne źródła danych, użyj IQueryable

Talha
źródło
11

Zasadnicza różnica polega na tym, że IEnumerable wylicza wszystkie swoje elementy przez cały czas, podczas gdy IQueryable wylicza elementy, a nawet robi inne rzeczy na podstawie zapytania. Zapytanie jest wyrażeniem (reprezentacją danych kodu .Net), które IQueryProvider musi zbadać / zinterpretować / skompilować / cokolwiek, aby wygenerować wyniki.

Posiadanie wyrażenia zapytania daje dwie korzyści.

Pierwszą zaletą jest optymalizacja. Ponieważ modyfikatory, takie jak „Where”, są zawarte w wyrażeniu zapytania, IQueryProvider może zastosować optymalizacje niemożliwe w innym przypadku. Zamiast zwracać wszystkie elementy, a następnie wyrzucać większość z nich ze względu na klauzulę „Where”, dostawca mógłby użyć tabeli skrótów do zlokalizowania elementów z danym kluczem.

Drugą zaletą jest elastyczność. Ponieważ wyrażenia są strukturami danych, które można eksplorować, można na przykład serializować zapytanie i wysłać je do maszyny zdalnej (np. Linq-to-sql).

Craig Gidney
źródło
1

Po pierwsze, IEnumerable znajdują się w przestrzeni nazw System.Collections, podczas gdy IQueryable znajdują się w przestrzeni nazw System.Linq. Jeśli używasz IEnumerable podczas odpytywania danych z kolekcji w pamięci, takich jak lista, kolekcja tablic itp. A podczas odpytywania danych z kolekcji poza pamięcią (takich jak zdalna baza danych, usługa), używasz IQueryable. Ponieważ podczas wykonywania zapytań dotyczących danych z bazy danych IEnumerable wykonuje zapytanie wybierające po stronie serwera, ładuje dane do pamięci po stronie klienta, a następnie filtruje dane. Dlatego wykonuje więcej pracy i staje się powolny. Podczas odpytywania danych z bazy danych IQueryable wykonuje zapytanie wybierające po stronie serwera ze wszystkimi filtrami. Dlatego wykonuje mniej pracy i staje się szybki.

Nayeem Mansoori
źródło