2011-07-23 14 views
9

Próbuję utworzyć dostawcę LINQ. Korzystam z przewodnika LINQ: Building an IQueryable provider series i dodałem kod do LINQ: Budowanie dostawcy IQueryable - Część IV.W jaki sposób wyrażenie LINQ wie, że Where() występuje przed Select()?

Czuję, jak działa i jaki jest pomysł. Teraz utknąłem na problemie, który nie jest problemem z kodem, ale bardziej na zrozumieniu.

mam wystrzelenie to stwierdzenie:

QueryProvider provider = new DbQueryProvider(); 
Query<Customer> customers = new Query<Customer>(provider); 

int i = 3; 
var newLinqCustomer = customers.Select(c => new { c.Id, c.Name}).Where(p => p.Id == 2 | p.Id == i).ToList(); 

jakoś kodu lub ekspresyjny, wie, że Where przychodzi przed Select. Ale jak i gdzie?

W kodzie, który sortuje wyrażenie, nie ma sposobu, w rzeczywistości ToString() w trybie debugowania, pokazuje, że Select jest przed Where.

Próbowałem sprawić, by kod zawiódł. Normalnie zrobiłem najpierw Where, a następnie Select.

W jaki sposób wyrażenie to sortuje? Nie zrobiłem żadnej zmiany w kodzie w przewodniku.

+0

Co masz na myśli "gdzie jest przed wyborem"? Masz na myśli wygenerowany kod SQL? – svick

+0

Jedyne, co mogę myśleć to to, że może widzisz wygenerowany SQL ma SELECT i WHERE ponownie? W takim przypadku przypuszczam, że jest jakiś krok optymalizacji gdzieś w dostawcy Linq2Sql, który pobiera "SELECT Id, Name FROM" (SELECT Id, Name FROM Customer WHERE Id = 2 || Id = @ i) 'i konwertuje go na' SELECT Id, nazwa od klienta WHERE Id = 2 || Id = @ i' - ale czy to właśnie widzisz i czy o to pytasz? – Stuart

+0

Znasz [re-linq] (http://relinq.codeplex.com/), prawda? Nie zamierzam wymyślać koła, mam nadzieję :-) – xanatos

Odpowiedz

10

wyrażenia są „interpretować”, „przetłumaczone” lub „stracony” w kolejności ich pisać - tak Where robi nie przyjść przed Select


Jeśli wykonanie:

 var newLinqCustomer = customers.Select(c => new { c.Id, c.Name}) 
             .Where(p => p.Id == 2 | p.Id == i).ToList(); 

Następnie Where jest wykonywany na IEnumerable lub IQueryable anonimowego typu.


Jeśli wykonanie:

 var newLinqCustomer = customers.Where(p => p.Id == 2 | p.Id == i) 
             .Select(c => new { c.Id, c.Name}).ToList(); 

Następnie Where jest wykonywany na IEnumerable lub IQueryable typu klienta.

Jedyne, co mogę myśleć to to, że może widzisz wygenerowany kod SQL, w którym SELECT i WHERE zostały zmienione? W takim przypadku mogę zgadnąć, że istnieje krok optymalizacji gdzieś w dostawcy (np.) LINQ to SQL, który pobiera SELECT Id, Name FROM (SELECT Id, Name FROM Customer WHERE Id=2 || [email protected]) i konwertuje go na SELECT Id, Name FROM Customer WHERE Id=2 || [email protected] - ale musi to być optymalizacja specyficzna dla dostawcy.

+0

Nie rozumiem odpowiedzi. Czym różnią się "wykonywane na IQueryable" i "wykonywane w LinqToSQL"? – svick

+0

Przepraszam - uporządkowałem to teraz. Jak już wspomniałem w swoim komentarzu do tego pytania, mogę sobie tylko wyobrazić, że OP widzi jakąś optymalizację przeprowadzoną w jakimkolwiek dostawcy linq, którego obecnie szuka - ale nie mamy tego szczegółu z jego pytania. – Stuart

+0

Jeśli filtr wyboru został uruchomiony przed miejscem, muszę go włączyć w kodzie, przez punkt przerwania, ale nie mogę. Mówisz, że jeśli zrobię najpierw wybierz, to gdzie jest to zrobić na typie anonimowym, ale nie ma metody połączenia z nazwą Wybierz, jak to możliwe? I –

4

Nie, w ogólnym przypadku (np. LINQ to Objects) wybór zostanie wykonany przed instrukcją where. Pomyśl, że to jest potok, twoim pierwszym krokiem jest transformacja, a drugi filtr. Nie odwrotnie, jak by było, gdybyś napisał Gdzie ... Wybierz.

Teraz dostawca LINQ ma swobodę poruszania się po drzewie ekspresji i optymalizowania go zgodnie z oczekiwaniami. Należy jednak pamiętać, że nie można zmienić semantyki wyrażenia. Oznacza to, że inteligentny dostawca LINQ to SQL spróbuje pobrać tyle klauzul, ile można do zapytania SQL, aby zmniejszyć ilość danych przesyłanych przez sieć.Należy jednak pamiętać o: the example from Stuart: Nie wszyscy dostawcy zapytań są sprytni, częściowo dlatego, że wykluczenie skutków ubocznych w wyniku zmiany kolejności zapytań nie jest tak proste, jak się wydaje.

+0

Nie sądzę, aby Twój pierwszy akapit był poprawny. Klauzule "Wybierz" i "Gdzie" są tylko projekcjami i filtrami, a dla zachowania semantyki muszą występować w podanej kolejności. Nie ma "ogólnego przypadku", który występuje przed drugim. Jest to kolejność, w jakiej oryginalna kwerenda została zapisana. – Enigmativity

Powiązane problemy