2010-12-10 14 views
6

Jaka jest korzyść z pisania niestandardowego dostawcy LINQ przez napisanie prostej klasy, która implementuje IEnumerable?Po co pisać niestandardowego dostawcę LINQ?

Na przykład ten pokazuje Linq2Excel quesiton:

var book = new ExcelQueryFactory(@"C:\Users.xls"); 
var administrators = from x in book.Worksheet<User>() 
        where x.Role == "Administrator" 
        select x; 

Ale jakie są korzyści nad "naiwnej" Wdrożenie jako IEnumerable?

+0

Nie wiem, dlaczego linq-to-excel korzysta z IQueryable, ale zdarzają się przypadki, w których kod jest znacznie szybszy. – CodesInChaos

Odpowiedz

11

Celem dostawcy Linq jest zasadniczo "przetłumaczenie" drzewek wyrażeń Linq (które są budowane za kulisami zapytania) na macierzysty język zapytania źródła danych. W przypadkach, gdy dane są już w pamięci, nie potrzebujesz dostawcy Linq; Obiekty Linq 2 są w porządku. Jeśli jednak używasz Linq do komunikowania się z zewnętrznym magazynem danych, takim jak DBMS lub chmura, jest to absolutnie niezbędne.

Podstawową przesłanką każdej struktury zapytań jest to, że silnik źródła danych powinien wykonywać jak najwięcej pracy i zwracać tylko te dane, które są potrzebne klientowi. Dzieje się tak, ponieważ zakłada się, że źródło danych najlepiej wie, jak zarządzać przechowywanymi danymi, a ponieważ transport danych w sieci jest stosunkowo drogi, należy go zminimalizować. Teraz w rzeczywistości ta druga część to "zwróć tylko dane żądane przez klienta"; serwer nie może odczytać umysłu twojego programu i wiedzieć, czego naprawdę potrzebuje; może dać tylko to, o co jest proszony. Oto, gdzie inteligentny dostawca Linq absolutnie wieje "naiwne" wdrożenie. Używając strony IQueryable Linq, która generuje drzewa ekspresji, dostawca Linq może przetłumaczyć drzewo ekspresji na, powiedzmy, instrukcję SQL, którą DBMS użyje do zwrócenia rekordów, o które prosił klient w instrukcji Linq. Naiwna implementacja wymagałaby pobrania WSZYSTKICH rekordów za pomocą jakiejś szerokiej instrukcji SQL, w celu dostarczenia klientowi listy obiektów znajdujących się w pamięci, a następnie cała praca związana z filtrowaniem, grupowaniem, sortowaniem itp. Jest wykonywana przez klienta.

Załóżmy na przykład, że używasz Linq, aby uzyskać rekord z tabeli w DB za pomocą klucza głównego. Dostawca Linq mógłby przetłumaczyć dataSource.Query<MyObject>().Where(x=>x.Id == 1234).FirstOrDefault() na "SELECT TOP 1 * z MyObjectTable WHERE Id = 1234". To zwraca zero lub jeden rekord."Naiwna" implementacja prawdopodobnie wyśle ​​serwerowi zapytanie "SELECT * FROM MyObjectTable", a następnie skorzystaj z IEnumerable strony Linq (która działa na klasach w pamięci), aby wykonać filtrowanie. W oświadczeniu, które spodziewasz się uzyskać wyniki 0-1 z tabeli z 10 milionami rekordów, które z nich mogłoby zrobić to zadanie szybciej (lub nawet pracować w ogóle, bez wyczerpania pamięci)?

7

Nie musisz pisać dostawcy LINQ, jeśli chcesz tylko użyć funkcji LINQ-to-Object (tj. foreach-like) do swoich celów, która w większości działa na listach w pamięci.

Musisz do trzeba napisać dostawcę LINQ, jeśli chcesz analizować drzewo wyrażeń w celu przetłumaczenia go na coś innego, np. SQL. Wymieniony program ExcelQueryFactory działa na przykład w połączeniu OLEDB. To prawdopodobnie oznacza, że ​​nie trzeba ładować całego pliku Excela do pamięci podczas sprawdzania jego danych.

3

Ogólna wydajność. Jeśli masz jakiś indeks, możesz wykonać zapytanie znacznie szybciej niż to, co jest możliwe na prostym IEnumerable<T>.

Linq-To-Sql jest tego dobrym przykładem. Tutaj przekształcasz instrukcję linq na inną w celu zrozumienia przez serwer SQL. Tak więc serwer wykona filtrowanie, porządkowanie, ... używanie indeksów i nie musi wysyłać całej tabeli do klienta, który następnie wykonuje to za pomocą linq-to-objects.

Ale są prostsze przypadki, w których może on być przydatny również:

Jeśli masz indeksu drzewa nad propery Time następnie zapytanie zakres jak .Where(x=>(x.Time>=now)&&(x.Time<=tomorrow)) można zoptymalizować dużo, i nie trzeba iteracyjne nad każdy przedmiot w przeliczalnym.

1

LINQ zapewni odroczone wykonanie w maksymalnej możliwej wysokości w celu poprawy wydajności.

IEnumurable <> i IQueryable <> będą całkowicie zapewniać różne implementacje programów. IQueryable da natywną kwerendę, dynamicznie budując drzewo wyrażeń, co zapewnia dobrą wydajność, a następnie IEumumable.

http://msdn.microsoft.com/en-us/vcsharp/ff963710.aspx

jeśli nie jesteśmy pewni, możemy użyć var słowa kluczowego i dynamicznie będzie zainicjować najbardziej odpowiedni typ.

Powiązane problemy