Jaka jest różnica między IQueryable<T>
i IEnumerable<T>
?
Zobacz także Jaka jest różnica między IQueryable i IEnumerable, która pokrywa się z tym pytaniem.
Jaka jest różnica między IQueryable<T>
i IEnumerable<T>
?
Zobacz także Jaka jest różnica między IQueryable i IEnumerable, która pokrywa się z tym pytaniem.
Odpowiedzi:
Przede wszystkim, rozciąga się interfejs, więc coś można zrobić z „zwykły” , można również zrobić z .IQueryable<T>
IEnumerable<T>
IEnumerable<T>
IQueryable<T>
IEnumerable<T>
tylko ma GetEnumerator()
metody, która zwraca Enumerator<T>
na której można wywołać jego MoveNext()
metodę iterację sekwencji T .
To IQueryable<T>
, czego IEnumerable<T>
nie ma, to w szczególności dwie właściwości - jedna, która wskazuje na dostawcę zapytań (np. Dostawca LINQ na SQL), a druga wskazuje na wyrażenie zapytania reprezentujące IQueryable<T>
obiekt jako abstrakcyjne drzewo składni, które można przenosić w czasie wykonywania. zrozumiałe dla danego dostawcy zapytań (w przeważającej części nie można podać wyrażenia LINQ do SQL dostawcy LINQ do podmiotu bez zgłoszenia wyjątku).
Wyrażenie może być po prostu stałym wyrażeniem samego obiektu lub bardziej złożonym drzewem złożonego zestawu operatorów zapytań i operandów. Dostawca IQueryProvider.Execute()
lub IQueryProvider.CreateQuery()
metody zapytania są wywoływane z przekazanym do niego wyrażeniem , a następnie IQueryable
zwracany jest odpowiednio wynik zapytania lub inny .
AsQueryable()
po prostu rzutuje wyliczenie na kwerendę i zwraca ją, jeśli implementuje IQueryable
interfejs, w przeciwnym razie zawija go w ConstantExpression
, do którego odwołuje się zwrócony EnumerableQuery
obiekt.
Podstawowa różnica polega na tym, że operatory LINQ do IQueryable<T>
pobierania Expression
obiektów zamiast delegatów, co oznacza, że otrzymywana przez nie niestandardowa logika zapytań, np. Predykat lub selektor wartości, ma postać drzewa wyrażeń zamiast delegata do metody.
IEnumerable<T>
jest świetny do pracy z sekwencjami, które są iterowane w pamięci, ale IQueryable<T>
pozwala na brak pamięci, takie jak zdalne źródło danych, takie jak baza danych lub usługa internetowa.W przypadku, gdy wykonanie zapytania będzie wykonywane „w toku” , zwykle wszystko, czego potrzeba, to kod (jako kod) do wykonania każdej części zapytania.
Tam, gdzie wykonanie zostanie wykonane poza procesem , logika zapytania musi być reprezentowana w danych, tak aby dostawca LINQ mógł przekonwertować go na odpowiednią formę do wykonania braku pamięci - niezależnie od tego, czy jest to zapytanie LDAP, SQL lub cokolwiek innego.
Więcej w:
To fajne wideo na youtube, które pokazuje, jak różne są te interfejsy, warte obejrzenia.
Poniżej znajduje się długa opisowa odpowiedź na to pytanie.
Pierwszą ważną kwestią do zapamiętania jest IQueryable
dziedziczenie interfejsu IEnumerable
, więc cokolwiek IEnumerable
może zrobić, IQueryable
może również zrobić.
Istnieje wiele różnic, ale omówmy jedną wielką różnicę, która stanowi największą różnicę. IEnumerable
Interfejs jest przydatny, gdy twoja kolekcja jest ładowana za pomocą LINQ
lub Entity Framework i chcesz zastosować filtr do kolekcji.
Rozważ poniższy prosty kod, który wykorzystuje się IEnumerable
w ramach encji. Używa Where
filtra, aby uzyskać rekordy, których EmpId
jest 2
.
EmpEntities ent = new EmpEntities();
IEnumerable<Employee> emp = ent.Employees;
IEnumerable<Employee> temp = emp.Where(x => x.Empid == 2).ToList<Employee>();
To, gdzie filtr jest wykonywany po stronie klienta, gdzie IEnumerable
znajduje się kod. Innymi słowy wszystkie dane są pobierane z bazy danych, a następnie na jego klient skanuje i pobiera rekord EmpId
jest 2
.
Ale teraz patrz poniższy kod zmieniliśmy IEnumerable
się IQueryable
. Tworzy zapytanie SQL po stronie serwera i tylko niezbędne dane są wysyłane po stronie klienta.
EmpEntities ent = new EmpEntities();
IQueryable<Employee> emp = ent.Employees;
IQueryable<Employee> temp = emp.Where(x => x.Empid == 2).ToList<Employee>();
Różnica między IQueryable
i IEnumerable
dotyczy tego, gdzie wykonywana jest logika filtru. Jeden wykonuje po stronie klienta, a drugi w bazie danych.
Więc jeśli pracujesz tylko z gromadzeniem danych w pamięci, IEnumerable
to dobry wybór, ale jeśli chcesz zapytać o zbieranie danych, które jest połączone z bazą danych, `IQueryable jest lepszym wyborem, ponieważ zmniejsza ruch w sieci i wykorzystuje moc języka SQL.
IEnumerable: IEnumerable najlepiej nadaje się do pracy z kolekcją w pamięci (lub zapytaniami lokalnymi). IEnumerable nie przemieszcza się między elementami, jest tylko kolekcją do przodu.
IQueryable: IQueryable najlepiej nadaje się do zdalnego źródła danych, takiego jak baza danych lub usługa internetowa (lub zdalne zapytania). IQueryable to bardzo potężna funkcja, która umożliwia szereg interesujących scenariuszy odroczonego wykonania (takich jak zapytania stronicowania i oparte na kompozycji).
Więc jeśli musisz po prostu iterować kolekcję w pamięci, użyj IEnumerable, jeśli potrzebujesz wykonać dowolną manipulację z kolekcją, taką jak Zbiór danych i inne źródła danych, użyj IQueryable
W prawdziwym życiu, jeśli używasz ORM, takiego jak LINQ-to-SQL
W obu przypadkach, jeśli nie nazywamy ToList()
lub ToArray()
wówczas zapytanie wykonywane za każdym razem, gdy jest używany, więc, powiedzmy, masz IQueryable<T>
i wypełnić 4 Wykaz pól od niego, wtedy zapytanie zostanie uruchomione na bazie 4-krotnie.
Również jeśli rozszerzysz swoje zapytanie:
q.Where(x.name = "a").ToList()
Następnie z IQueryable wygenerowany SQL będzie zawierał „gdzie nazwa =„ a ”, ale przy IEnumerable wiele innych ról zostanie wycofanych z bazy danych, a następnie sprawdzenie .x.name =„ a ”zostanie wykonane przez .NET.
Poniższy mały test może pomóc zrozumieć jeden aspekt różnicy między IQueryable<T>
i IEnumerable<T>
. Powtórzyłem tę odpowiedź z tego postu, w którym próbowałem dodać poprawki do postu innej osoby
Utworzyłem następującą strukturę w DB (skrypt DDL):
CREATE TABLE [dbo].[Employee]([PersonId] [int] NOT NULL PRIMARY KEY,[Salary] [int] NOT NULL)
Oto skrypt wstawiania rekordów (skrypt DML):
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(1, 20)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(2, 30)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(3, 40)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(4, 50)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(5, 60)
GO
Teraz moim celem było po prostu uzyskanie 2 najlepszych rekordów z Employee
tabeli w bazie danych. Dodałem element ADO.NET Entity Data Model do mojej aplikacji konsoli wskazując na Employee
tabelę w mojej bazie danych i zacząłem pisać zapytania LINQ.
Kod trasy IQueryable :
using (var efContext = new EfTestEntities())
{
IQueryable<int> employees = from e in efContext.Employees select e.Salary;
employees = employees.Take(2);
foreach (var item in employees)
{
Console.WriteLine(item);
}
}
Kiedy zacząłem uruchamiać ten program, rozpocząłem także sesję profilowania zapytań SQL na mojej instancji SQL Server i oto podsumowanie wykonania:
SELECT TOP (2) [c].[Salary] AS [Salary] FROM [dbo].[Employee] AS [c]
Po prostu IQueryable
jest wystarczająco inteligentny, aby zastosować Top (2)
klauzulę po stronie samego serwera bazy danych, dzięki czemu łączy tylko 2 z 5 rekordów. Dalsze filtrowanie w pamięci nie jest wcale wymagane po stronie komputera klienckiego.
Kod dla IEnumerable route :
using (var efContext = new EfTestEntities())
{
IEnumerable<int> employees = from e in efContext.Employees select e.Salary;
employees = employees.Take(2);
foreach (var item in employees)
{
Console.WriteLine(item);
}
}
Podsumowanie wykonania w tym przypadku:
SELECT [Extent1].[Salary] AS [Salary]
FROM [dbo].[Employee] AS [Extent1]
Teraz IEnumerable
przyniesiono wszystkie 5 rekordów obecnych w Salary
tabeli, a następnie przeprowadzono filtrowanie w pamięci na komputerze klienckim, aby uzyskać 2 najlepsze rekordy. Tak więc więcej danych (w tym przypadku 3 dodatkowe rekordy) zostało niepotrzebnie przesłanych przewodowo.
Oto, co napisałem w podobnym poście (na ten temat). (I nie, zwykle nie cytuję siebie, ale są to bardzo dobre artykuły).
„Ten artykuł jest pomocny: IQueryable vs IEnumerable w LINQ-to-SQL .
Cytując ten artykuł: „Zgodnie z dokumentacją MSDN wywołania w IQueryable działają w oparciu o wewnętrzne drzewo wyrażeń. „Te metody, które rozszerzają IQueryable (Of T), nie wykonują żadnych zapytań bezpośrednio. Zamiast tego ich funkcją jest zbudowanie obiektu Expression, który jest drzewem wyrażeń reprezentującym zapytanie skumulowane.”
Drzewa wyrażeń są bardzo ważną konstrukcją w języku C # i na platformie .NET. (Są one ogólnie ważne, ale C # czyni je bardzo przydatnymi.) Aby lepiej zrozumieć różnicę, zalecam przeczytanie o różnicach między wyrażeniami i wyrażeniami w oficjalnej specyfikacji C # 5.0 tutaj. W przypadku zaawansowanych koncepcji teoretycznych, które rozgałęziają się w rachunku lambda, wyrażenia umożliwiają obsługę metod jako obiektów pierwszej klasy. Różnica między IQueryable i IEnumerable skupia się wokół tego punktu. IQueryable buduje drzewa wyrażeń, podczas gdy IEnumerable nie działa, przynajmniej ogólnie dla tych z nas, którzy nie pracują w tajnych laboratoriach Microsoft.
Oto kolejny bardzo przydatny artykuł, który wyszczególnia różnice z perspektywy push and pull. (Przez „push” vs. „pull” mam na myśli kierunek przepływu danych. Reaktywne techniki programowania dla .NET i C #
Oto bardzo dobry artykuł, który szczegółowo opisuje różnice między wyrażeniem lambdas a wyrażeniem lambdas i omawia pojęcia warkocza wyrażeń bardziej szczegółowo: Ponowne odwiedzanie delegatów C #, drzew wyrażeń i wyrażeń lambda vs. wyrażeń lambda. . ”
Używamy IEnumerable
i IQueryable
manipulujemy danymi pobieranymi z bazy danych. IQueryable
dziedziczy po IEnumerable
, więc IQueryable
zawiera wszystkie IEnumerable
funkcje. Główną różnicą pomiędzy IQueryable
i IEnumerable
jest IQueryable
Wykonuje kwerendy z filtrami natomiast IEnumerable
wykonuje zapytanie, a następnie filtruje dane w oparciu o warunki.
Znajdź bardziej szczegółowe zróżnicowanie poniżej:
IEnumerable
IEnumerable
istnieje w System.Collections
przestrzeni nazwIEnumerable
wykonaj wybrane zapytanie po stronie serwera, załaduj dane do pamięci po stronie klienta, a następnie przefiltruj daneIEnumerable
jest odpowiedni do tworzenia zapytań o dane ze zbiorów w pamięci, takich jak List, ArrayIEnumerable
jest korzystny dla zapytań LINQ to Object i LINQ to XMLIQueryable
IQueryable
istnieje w System.Linq
przestrzeni nazwIQueryable
wykonuje „wybierz zapytanie” po stronie serwera ze wszystkimi filtramiIQueryable
nadaje się do wysyłania zapytań o dane z kolekcji zewnętrznych (takich jak zdalna baza danych, usługa)IQueryable
jest korzystny dla zapytań LINQ do SQLIEnumerable
Jest więc ogólnie używany do radzenia sobie z kolekcją w pamięci, podczas gdy IQueryable
jest ogólnie używany do manipulowania kolekcjami.
Zarówno IEnumerable, jak i IQueryable służą do przechowywania kolekcji danych i wykonywania operacji manipulacji danymi, na przykład filtrowania kolekcji danych. Tutaj możesz znaleźć najlepsze porównanie różnic z przykładem. http://www.gurujipoint.com/2017/05/difference-between-ienumerable-and.html
IQueryable jest szybszy niż IEnumerable, jeśli mamy do czynienia z ogromnymi ilościami danych z bazy danych, ponieważ IQueryable pobiera tylko wymagane dane z bazy danych, gdzie jako IEnumerable pobiera wszystkie dane bez względu na konieczność z bazy danych
ienumerable: kiedy chcemy poradzić sobie z pamięcią wewnętrzną, tzn. bez połączenia danych iqueryable: kiedy mamy do czynienia z serwerem sql, tj. z ilistem połączenia danych: operacje takie jak dodawanie obiektu, usuwanie obiektu itp