Jakie jest zastosowanie IQueryable
w kontekście LINQ?
Czy jest używany do opracowywania metod rozszerzenia lub w jakimkolwiek innym celu?
źródło
Jakie jest zastosowanie IQueryable
w kontekście LINQ?
Czy jest używany do opracowywania metod rozszerzenia lub w jakimkolwiek innym celu?
Odpowiedź Marca Gravella jest bardzo kompletna, ale pomyślałem, że dodam coś o tym również z punktu widzenia użytkownika ...
Główną różnicą z punktu widzenia użytkownika jest to, że kiedy korzystasz IQueryable<T>
(z dostawcą, który poprawnie obsługuje rzeczy), możesz zaoszczędzić wiele zasobów.
Na przykład, jeśli pracujesz przeciwko zdalnej bazie danych, z wieloma systemami ORM, masz opcję pobierania danych z tabeli na dwa sposoby, jeden zwracający IEnumerable<T>
, a drugi zwracający IQueryable<T>
. Załóżmy na przykład, że masz tabelę Produkty i chcesz uzyskać wszystkie produkty, których koszt wynosi> 25 USD.
Jeśli zrobisz:
IEnumerable<Product> products = myORM.GetProducts();
var productsOver25 = products.Where(p => p.Cost >= 25.00);
To, co się tutaj dzieje, polega na tym, że baza danych ładuje wszystkie produkty i przekazuje je do twojego programu. Twój program następnie filtruje dane. Zasadniczo baza danych wykonuje SELECT * FROM Products
i zwraca KAŻDY produkt.
Z odpowiednim IQueryable<T>
dostawcą możesz natomiast:
IQueryable<Product> products = myORM.GetQueryableProducts();
var productsOver25 = products.Where(p => p.Cost >= 25.00);
Kod wygląda tak samo, ale różnica polega na tym, że SQL zostanie wykonany SELECT * FROM Products WHERE Cost >= 25
.
Z twojego POV jako programisty wygląda to tak samo. Jednak z punktu widzenia wydajności możesz zwrócić tylko 2 rekordy w sieci zamiast 20 000 ....
IQueryable<Product>
- byłaby specyficzna dla Twojego ORM lub repozytorium itp.foreach
lub zadzwońToList()
), tak naprawdę nie trafisz do bazy danych.Zasadniczo jego zadanie jest bardzo podobne do
IEnumerable<T>
- reprezentowania źródła danych, które można zapytać - różnica polega na tym, że różne metody LINQ (włączoneQueryable
) mogą być bardziej szczegółowe, aby zbudować zapytanie przy użyciuExpression
drzew, a nie delegatów (coEnumerable
wykorzystuje).Drzewa wyrażeń mogą być sprawdzane przez wybranego dostawcę LINQ i przekształcane w rzeczywiste zapytanie - chociaż samo w sobie jest czarną sztuką.
To naprawdę zależy od tego
ElementType
,Expression
iProvider
- ale w rzeczywistości rzadko musisz się tym przejmować jako użytkownik . Tylko osoba wdrażająca LINQ musi znać krwawe szczegóły.Re komentarze; Nie jestem do końca pewien, czego chcesz na przykład, ale rozważ LINQ-to-SQL; centralnym obiektem tutaj jest
DataContext
symbol reprezentujący nasze opakowanie bazy danych. Zwykle ma właściwość na tabelę (na przykładCustomers
) i implementuje tabelęIQueryable<Customer>
. Ale nie używamy tak dużo bezpośrednio; rozważać:staje się (przez kompilator C #):
który jest ponownie interpretowany (przez kompilator C #) jako:
Co ważne, metody statyczne w
Queryable
drzewach wyrażeń, które - zamiast zwykłej IL, są kompilowane do modelu obiektowego. Na przykład - wystarczy spojrzeć na „Where”, co daje nam coś porównywalnego do:Czy kompilator nie zrobił dla nas wiele? Ten model obiektowy można rozerwać na części, sprawdzić pod kątem jego znaczenia i złożyć ponownie w całość za pomocą generatora TSQL - dając coś takiego:
(ciąg może skończyć jako parametr; nie pamiętam)
Nie byłoby to możliwe, gdybyśmy właśnie skorzystali z usług delegata. I to jest punkt
Queryable
/IQueryable<T>
: zapewnia punkt wejścia do korzystania z drzew wyrażeń.Wszystko to jest bardzo złożone, więc kompilator sprawia, że jest to dla nas przyjemne i łatwe.
Aby uzyskać więcej informacji, zobacz „ C # in Depth ” lub „ LINQ in Action ”, z których oba zapewniają omówienie tych tematów.
źródło
Chociaż Reed Copsey i Marc Gravell już opisali wystarczająco dużo
IQueryable
(i równieżIEnumerable
), chcę dodać tutaj trochę więcej, podając mały przykładIQueryable
iIEnumerable
wielu użytkowników o to poprosiłoPrzykład : Utworzyłem dwie tabele w bazie danych
Klucz podstawowy (
PersonId
) w tabeliEmployee
jest również kluczem kuźni (personid
) w tabeliPerson
Następnie dodałem model encji ado.net do mojej aplikacji i utworzyłem poniżej klasę usług
zawierają ten sam linq. Wywołał
program.cs
jak zdefiniowano poniżejWynik jest oczywiście taki sam dla obu
Pytanie brzmi, jaka jest / gdzie jest różnica? Wydaje się, że nie ma to żadnej różnicy, prawda? Naprawdę!!
Przyjrzyjmy się zapytaniom sql wygenerowanym i wykonanym przez zespół jednostek 5 w tym okresie
I Część możliwa do wykonania
IEnumerowalna część wykonania
Wspólny skrypt dla obu części wykonania
Więc masz teraz kilka pytań, pozwól mi je odgadnąć i spróbuj na nie odpowiedzieć
Dlaczego generowane są różne skrypty dla tego samego wyniku?
Dowiedzmy się tutaj kilka punktów,
wszystkie zapytania mają jedną wspólną część
WHERE [Extent1].[PersonId] IN (0,1,2,3)
czemu? Ponieważ zarówno funkcję
IQueryable<Employee> GetEmployeeAndPersonDetailIQueryable
iIEnumerable<Employee> GetEmployeeAndPersonDetailIEnumerable
odSomeServiceClass
zawiera jedną wspólną linię zapytań LINQwhere employeesToCollect.Contains(e.PersonId)
Dlaczego więc
AND (N'M' = [Extent1].[Gender])
brakuje części wIEnumerable
części wykonawczej, podczas gdy w obu wywołaniach funkcji użyliśmyWhere(i => i.Gender == "M") in
programu.cs`To, co robi ramka encji, gdy wywoływana
IQueryable
metoda, działa na instrukcję linq zapisaną w metodzie i próbuje dowiedzieć się, czy w zestawie wyników zdefiniowano więcej wyrażeń linq, a następnie gromadzi wszystkie zdefiniowane zapytania linq, dopóki wynik nie będzie wymagał pobrania i konstruuje bardziej odpowiednie sql zapytanie do wykonania.Zapewnia wiele korzyści, takich jak
jak tutaj w przykładzie serwer sql wrócił do aplikacji tylko dwa wiersze po wykonaniu IQueryable`, ale zwrócił TRZY wiersze dla zapytania IEnumerable dlaczego?
W przypadku
IEnumerable
metody, środowisko encji wzięło instrukcję linq zapisaną w metodzie i konstruuje zapytanie SQL, gdy wynik musi zostać pobrany. nie zawiera reszty linq do konstruowania zapytania SQL. Podobnie jak tutaj, nie wykonuje się filtrowania na serwerze SQL w kolumniegender
.Ale wyniki są takie same? Ponieważ „IEnumerable filtruje wynik dalej na poziomie aplikacji po pobraniu wyniku z serwera SQL
Więc co powinien wybrać ktoś? Ja osobiście wolę zdefiniować wynik funkcji, ponieważ
IQueryable<T>
ponieważ ma wiele zalet, naIEnumerable
przykład, możesz dołączyć dwie lub więcej funkcji IQueryable, które generują bardziej szczegółowy skrypt do serwera SQL.W tym przykładzie widać, że
IQueryable Query(IQueryableQuery2)
generuje bardziej szczegółowy skrypt,IEnumerable query(IEnumerableQuery2)
który jest o wiele bardziej akceptowalny z mojego punktu widzenia.źródło
Umożliwia dalsze zapytania w dalszej linii. Jeśli jest to poza granicami usługi, powiedzmy, że użytkownik tego obiektu IQueryable będzie mógł zrobić z nim więcej.
Na przykład, jeśli używasz leniwego ładowania z nhibernate, może to powodować ładowanie wykresu, gdy / jeśli to konieczne.
źródło