Natrafiłem na pytanie, na które odpowiedzi nie potrafię znaleźć na google. Microsoft.Azure.Cosmos.Container
ma metodę GetItemLinqQueryable()
, która umożliwia odpytywanie Cosmos DB za pomocą LINQ. Where()
obecne w IOrderedTemplate<T>
zwracanym przez GetItemLinqQueryable()
ma dwie podstawowe wersje, jedna przyjmuje jako argument Func<T, bool>
, druga Expression<Func<T, bool>>
. O ile działanie drugiego overloada w miarę rozumiem, bo działa przy tłumaczeniu LINQ na "sql" tak samo, jak dzieje się to dla EF i SQL Server, o tyle pierwszy (przyjmujący Func<T, bool>
) jest dla mnie zagadką.
Zdrowy rozsądek podpowiada mi, że żeby filtrować dane za pomocą metody po stronie C#, wszystkie dane muszą być ściągnięte i zadziała to jak linq-to-object, czyli najwolniejszy możliwy sposób przetwarzania danych z bazy.
Czy mam rację?
A nie jest tak, że Func kompilator domyślnie rzutuje do Expression? Expression służy temu, że mógłbyś zrobić np. predefiniowane zapytanie i złożyć lambdę ręcznie.
Co do zasady działania, framework bada Expression Tree i na jego podstawie buduję zapytanie do docelowej bazy.
Nie da się zrzutować ani przekonwertować Func
na Expression
, działają kompletnie inaczej. Acz zapewne da się Expression
na Func
.
EF przy kompilowaniu lambdy do sql poleci wyjątek, jeśli w expression użyjesz metody spoza dozwolonego setu (SqlFunctions
i SqlFunctions2
bodajże), a to dlatego, że linq-to-sql rządzi się innymi, dużo bardziej restrykcyjnymi prawami niż linq-to-objects. Zresztą tak na logikę: jak sobie wyobrażasz przetłumaczenie na sql metody jakiegoś obiektu, która może używać innych metod innych obiektów, a wszystkie te obiekty mogą mieć jakiś stan i dalsze zależności?
Z konwersją mogłem faktycznie przekręcić, ale jak dziala Entity Framework? :) Wychodzisz np. od DbSet.Where, przekazujesz lambdy, framework przechodzi po Expression Tree i zmienia to na SQL.