IEnumerable a IQueryable

IEnumerable a IQueryable
UN
  • Rejestracja:ponad 8 lat
  • Ostatnio:około 3 lata
  • Postów:18
0

Cześć, mam pytanie dotyczące interfejsów IEnumerable i IQueryable. Napisałem prosty program z zapytaniem do bay z użyciem tych dwóch interfejsów. Rozumiem, że główna różnica pomiędzy nimi jest to, że w przypadku IQueryable dane zostaną filtrowane na serwerze a w przypadku IEnumerable lokalnie. Postanowiłem jednak napisać do samo zapytanie z wykorzystniem tych dwóch interfejsów i obserwować róch na sieci.

Kopiuj
            IEnumerable<byte?> employeeIEnumberable =
                dc.Adult_Census_Income_Binary_Classification_datasets.
                Select(p => p.age).Take(10);

            IQueryable<byte?> employeeIQueryable =
                dc.Adult_Census_Income_Binary_Classification_datasets.
                Select(p => p.age).Take(10);
Kopiuj
            IEnumerable<byte?> employeeIEnumberable =
                dc.Adult_Census_Income_Binary_Classification_datasets.
                Select(p => p.age);
            employeeIEnumberable.Take(10);

            IQueryable<byte?> employeeIQueryable =
                dc.Adult_Census_Income_Binary_Classification_datasets.
                Select(p => p.age);
            employeeIQueryable.Take(10);

W pierwszym przypadku ruch na siecie w dwóch przypadkach jest taki sam. W drugim przypadku przy IEnumerable ruch ten jest znacznie większy, w przypadku IQueryable ruch pozostaje na niskim poziomie. I tutaj mam pytnie właściwie czemu w pierwszym przypadku ruch przy IEnumerable był na niskim poziomie skoro filtrowanie wyników przy użyciu tego interfejsu powinno odbyć się lokalnie?

SO
  • Rejestracja:ponad 10 lat
  • Ostatnio:około rok
1
uniqa napisał(a):

I tutaj mam pytnie właściwie czemu w pierwszym przypadku ruch przy IEnumerable był na niskim poziomie skoro filtrowanie wyników przy użyciu tego interfejsu powinno odbyć się lokalnie?

Bo w pierwszym przypadku korzystasz z IQueryable a dopiero po uzyskaniu wyników z bazy rzutujesz na IEnumerable.

ŁF
Moderator
  • Rejestracja:ponad 22 lata
  • Ostatnio:około 19 godzin
2

IEnumerable<T> działa na linq-to-objects, IQueryable<T> to link-to-sql.
Oznacza to, że dopóki działasz na IQueryable<T> całość lambd ze wszystkich warunków, grupowań, sortowań itp. będzie przetłumaczona na sql. Z tego powodu też istnieją duże ograniczenia na to, co w takich lambdach może się znaleźć (zestaw metod, które możesz użyć, jest predefiniowany). Zaletą jest to, że przetwarzanie danych zrzucasz na bazę danych, czyli używasz młotka do wbijania gwoździ (jak zawsze istnieją wyjątki, czasem opłaca się pobrać więcej danych i obrabiać w kliencie, czyli tutaj w C#, ale żeby to stwierdzić, to i tak trzeba wygenerować zapytanie i przeanalizować jego plan wykonania), ponadto przesyłasz tylko tyle danych, ile trzeba.
Jeśli jakikolwiek wynik zapytania zrzutujesz na IEnumerable<T>, to każde (!) odwołanie do wyniku spowoduje zassanie z bazy wszystkich rekordów. Jeśli na IEnumerable<T> wykonasz podzapytanie (np. Take), to pobrane będą wszystkie rekordy określone w IEnumerable<T>, a dopiero na nich odbędzie się filtrowanie, sortowanie itp. Wbijasz wszystkie gwoździe, chociaż potrzebujesz tylko jeden.
Ponieważ IEnumerable<T> iteruje po danych przy każdym odwołaniu spowoduje to kolejne wykonania sql za nim stojącego. Z tego powodu nie polecam używania IEnumerable<T> w ogóle. Albo IQueryable<T>, albo ICollection<T>, albo IList<T>

[edit]
Nie odpowiedziałem na zadane pytanie ;-) Więc "czemu w pierwszym przypadku ruch przy IEnumerable był na niskim poziomie"? Bo rzutuwanie na IEnumerable odbywa się dopiero po wykonaniu Take(). Samo Take() wykonuje się na IQueryable.


edytowany 2x, ostatnio: ŁF

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.