To O/RM or not to O/RM?
Zdaję sobie sprawę, że postem tym mogę wywołać świętą wojnę religijną, ale - niech tam - zaryzykuje. Do napisania na ten temat skłoniła mnie notatka znaleziona przeze mnie ostatnio w sieci. Notatka ta zajmowała się porównywaniem wydajności EDM (Linq to Entities) z NHibernate. Temat ten był bardzo gorący jakiś czas temu. Teraz nieco ostygł, ale wciąż (teraz pewnie z racji zbliżającego się EDM 2.0) trzyma się nieźle.
No więc do rzeczy: co jest szybsze - EDM czy NHibernate? A może wszystkie O/RM-y są złe i należy używać DataReader-a? A może Linq2SQL jest dobrym kompromisem?
(spoiler space:P)No więc moim zdaniem pytanie to jest pozbawione sensu. Badanie wydajności NHibernate w porównaniu do EDM jest pozbawione sensu. Porównywanie jakiegokolwiek O/RM-a z DataReader-em jest totalnie pozbawione sensu.
Przecież nikt nie powie klientowi: dostęp do danych tej aplikacji wykonuje 50/500/5000 (niepotrzebne skreślić) operacji na sekundę. Klienta naprawdę nie interesuje, jak wydajna jest jego aplikacja, dopóki jest na tyle wydajna, aby go nie denerwować. Nikt nie bada czy strona WWW przeładowuje się 0,1 czy 0,05 sekundy, chociaż to stuprocentowa różnica.
Tak więc pierwsza moja teza:
jeśli Twój system nie jest systemem przetwarzającym dane w masowy sposób, OR/M napewno jest dobrym rozwiązaniem. Zastanówcie się co jest tańsze: zakup dwukrotnie mocniejszej maszyny dla postawienia bazy danych, czy zatrudnienie kilku dodatkowych programistów.
Kolejna kwestia - jeśli już OR/M, to jaki? Dla celów tego pytania potraktujmy Linq2SQL jako ubogiego OR/M-a.
Linq2SQL jest zdecydowanie najszybsze z całej trójki. Szybkość ta jednak ma swoją cenę. Ceną tą jest wymuszenie maksymalnego podobieństwa pomiędzy modelem danych w bazie, a modelem w kodzie: tabele mapowane są jeden-do-jednego z klasami, podobnie (domyślnie) jest z kolumnami i właściwościami. Dzięki temu silnik Linq2SQL może lepiej optymalizować swoje zapytania. Nie musi też wykonywać skomplikowanych transformacji. W bezwględnych liczbach działa najszybciej. Zastanówmy się jednak, co by było gdybyśmy chcieli, w naszej nietrywialnej aplikacji, posiadać skomplikowany obiektowy model domeny. Ale to taki naprawde bogaty. Mapowanie go jeden-do-jeden do tabel może doprowadzić do tego, że, mimo iż pojedyncze zapytania będą realizowane szybko, będzie ich tak dużo i będą tak nieoptymalne (logicznie), że całość działać będzie wolniej, niż gdybyśmy użyli bardziej zaawansowanego OR/M-a.
Teza druga:
dobre OR/M-y pozwalają nie tylko na mapowanie danych relacyjnych na obiekty, ale także
zapewniaja, że oba modele - relacyjny i obiektowy - będą mogły być zrealizowane zgodnie z najlepszymi praktykami związanymi z ich dziedzinami. Kiepski OR/M (Linq2SQL) wymusza dostosowanie się jednego modelu do drugiego: ucierpi na tym przejrzystość, a może nawet i wydajność.
Na koniec zostawiłem sobie starcie gigantów, czyli EDM vs NHibernate. Z jednej strony bardzo mocne wsparcie Microsoft, z drugiej strony bardzo stabilny produkt open-source. Możliwości obu bibliotek są zbliżone, wydajność także. W tym wypadku moim zdaniem diabeł tkwi w szczegółach. Dwóch konkretnie:
- Wsparcie dla POCO
- Dostarczane narzędzie
NHibernate w swej filozofii opiera się na idei persystencji POCO. Dzięki temu naturalne wydaje się podejście z modelowaniem na poziomie kodu (C#) z poźniejszym wygenerowaniem schematu bazy danych. NHibernate zawiera od razu narzędzie, które pozwala na podstawie kodu i mapowań wygenerować automatycznie taki schemat.
Z drugiej strony, EDM nie wspiera POCO. Klasy modelu EDM muszą być albo narysowane, albo wygenerowane na podstawie istniejącej bazy danych. Można nawet napisać klasy modelu EDM "z palca". Fakt, że domyślnie wszystkie dane z kolumn są udostępniane jako publiczne właściwości, pozostaje jednak faktem - klasy EDM są "strukturami na sterydach".
Tak jak pisałem, różnica jest subtelna: nie w tym, na co pozwala dana biblioteka, ale raczej w tym, które podejście jest w niej preferowane. Według mnie definitywnie NHibernate promuje
bogaty model domeny, natomiast EDM - model
anemiczny, generowany na podstawie tabel. Co jest leszcze? - dopowiedżcie sobie sami:)