EF Core vs Dapper

0

Witam.
Piszę z kwestią, która już była parę razy poruszana w pomniejszych wątkach. Moje dwa poprzednie projekty korzystają z EF Core i miałem kilka "gwoździ", które rozwiązywałem na różne, szalone sposoby. Teraz stoję przed dylematem, czy dalej brnąć w EF Core, czy może spróbować oprzeć oprogramowanie na Dapperze, bo akurat Dappera znam. Brak elastyczności w przypadku EF trochę mnie boli, ponieważ tak jak zostało to napisane, w którymś z moich wątków - nie ma ogólnych zapytań SQL. Czyste query można sobie puścić z poziomu tabeli, a nie z poziomu całego contextu. Dapper, z drugiej strony, odstrasza mnie "strukturą" - dapper.contrib nie jest w stanie zapisać generycznych obiektów, trzeba gdzieś trzymać wszystkie stringi z zapytaniami. Takie mam doświadczenia z tymi technologiami. Jak żyć? Co wybrać?

4

My w pracy używamy mixu obu - zapis przez EF Core i odczyt zwykle przez Dappera. Tylko mamy osobne klasy do zapisu i odczytujemy to zupełnie innych klas (dokładnie takich jak w danej chwili potrzeba). Powiedzmy, że jest to CQRS (w jakiejś tam podstawowej wersji).
Tylko mamy to podzielone na niewielkie, podzielone na warstwy klasy i metody więc string z sqlem jest jeden w klasie, który robi dokładnie to co ta klasa potrzebuje, a nie, że wszystkie zapytania w aplikacji są wpakowane do gigantycznej klasy statycznej czy coś tego typu.

0

To zależy od projektu. Jeżeli masz mały projekt z małą bazą danych to używanie Dappera jest wyciąganiem armaty na wróbla. Przy większych projektach a w zasadzie przy dużych zapytaniach Dapper radzi sobie dużo lepiej niż EF. Najlepiej używać mix tych dwóch. Do małych zapytań EF, do dużych (w sensie obciążających) Dapper.

0

Pytanie teraz co to jest mały projekt? :-) Ogólnie i krótko pisząc - zarządzanie kontraktami na produkty pomiędzy firmami, z bazą plików (pdf, doc, jpg...) powiązanych z kontraktem lub produktem z uwzględnieniem uprawnień dla użytkowników do tych plików. Duży projekt, czy mały?

2
AdamWox napisał(a):

Pytanie teraz co to jest mały projekt? :-) Ogólnie i krótko pisząc - zarządzanie kontraktami na produkty pomiędzy firmami, z bazą plików (pdf, doc, jpg...) powiązanych z kontraktem lub produktem z uwzględnieniem uprawnień dla użytkowników do tych plików. Duży projekt, czy mały?

Mały/duży to indywidualna kwestia. Tak samo wielkość bazy też. Aczkolwiek możesz z grubsza oszacować jak duże będziesz miał zapytania w projekcie. Jeżeli znasz schemat bazy to na podstawie use casów możesz z grubsza pokminić ile będzie joinów między tabelami i jak są skomplikowane. Jeżeli schemat jest prosty (Users, Posts, UserRoles, Comments, etc) to EF sobie z tym poradzi. Jeżeli masz pewnie ze 100 tabel i z 10 joinów do zapytania to EF mówi pass.

2

Jeśli chcesz korzystać z EF i masz problem z jakimś jednym konkretnym zapytaniem to warto się zastanowić nad użyciem procedury składowanej i wykonania jej z poziomu EF. To daje równie mocną elastyczność jak Dapper.

3

Czy Dapper ma swój model bazy danych i mechanizm do jego aktualizacji?
Istotną częścią większości ORMów jest mechanizm zapewniający pewien poziom spójności pomiędzy kodem a bazą danych. Jeśli używasz podejścia database first i robisz zmiany w bazie, a potem aktualizujesz model bazy, to większość (jeśli nie wszystkie) zmian wyjdzie na etapie kompilacji. Zmienione nazwy tabel, pól, typów pól, parametry sp itp. To pozwala na zmniejszenie ilości błędów w kodzie (mniejsza regresja), więc jest bardzo dużą zaletą. Niestety cała infrastruktura ORM często zjada dużo zasobów i spowalnia komunikację z bazą danych, a generowane zapytania czasem są dalekie od optymalnych.
Pisanie zapytań bezpośrednio do bazy danych likwiduje ten problem, ale też zabiera kontrolę spójności z bazą danych. Dlatego moim zdaniem w dużych projektach najlepsze jest mieszanie obu podejść, czyli używanie dużego ORM wszędzie, gdzie nie powoduje to wąskich gardeł oraz małego mappera w takich miejscach. Przy małych projektach, gdy łatwiej zapanować nad całym kodem naraz, wybór EF/Dapper moim zdaniem powinno zależeć tylko od wymaganej wydajności.

Pamiętajmy, że w tych czasach słaba wydajność to czasem kwestia dokupienia kilku maszyn/dołożenia kilku procesorów, co zwykle jest tańsze niż dodatkowe godziny pracy programistów albo wkurzeni błędami klienci odchodzący do konkurencji.

0

U siebie też robię miks. Zacząłem od EfCore + nHibernate. Ale z nHibernate było duuużo problemów jak na moje założenia (za dużo robi), więc przesiadłem się na Dappera. EfCore jednak używam tylko do standardowych rzeczy (w stylu ogarnianie użytkowników, ról itd). Problem z Dapperem jest tylko taki, że czasem są potrzebne różne zapytania pod różne DBMS. Akurat w moim projekcie używam jednocześnie MSSQL i SQLite, co stanowi wyzwanie w pewnych momentach :) Ale idzie to opanować.

0
var napisał(a):

Jeśli chcesz korzystać z EF i masz problem z jakimś jednym konkretnym zapytaniem to warto się zastanowić nad użyciem procedury składowanej i wykonania jej z poziomu EF. To daje równie mocną elastyczność jak Dapper.

A co myślisz o używaniu do tego celu widoków? W ten sposób te skomplikowane joiny trzymamy po stronie bazy, ale wciąż możemy wykorzystać EF np. do filtrowania (co w większości przypadków już powinno generować proste query).

0

Widzę, że większość korzysta z obu rozwiązań. Teraz pytanie w kwestii Dappera i jego "struktury". Przyznaje się, bez bicia, że do tej pory robiłem klasę statyczną Queries i pakowałem wszystkie stringi z zapytaniami tam. Rozwiązanie, które zasugerował @mar-ek1 ma sens, tylko nie wiem, czy dobrze rozumiem. Jako statyczna właściwość modelu?

public class Product
{
   public int Id {get;set;}
   public string Name {get;set;}

   public static string GetAllQuery = "select * from Products";
   public static string GetByIdQuery = "select * from Products where Id = @Id";
   public static string GetByNameQuery = "select * from Products where Name = @Name";
}
1

Nie trzymam sqla w modelu bo to co jest w bazie może nie mieć nic wspólnego z tym co czytam.
Akurat w naszym przypadku mamy handlery/serwisy, które wyciągają konkretne rzeczy. Jak potrzebuję listę IDków userów z rolą "Tester" to mam klasę, która takie dane wyciąga i mapuje na odpowiednie DTO. Jak potrzebuję z tej samej tabeli wyciagnąć szczegóły aktualnego usera to mam kolejną klasę, która to robi, zwłaszcza, że te dane mogą być np. w 10 tabelach bo na te szczegóły może się składać liczba dodanych do niego projektów, nazwisko przełożonego, data ostatniego logowania i awatar. I w obu przypadkach czytam przypadkiem z tej samej tabeli, ale to są zupełnie inne dane i inne DTO więc i inne query i klasy, które to robią.

Model do zapisu ma tylko to co jest potrzebne do zapisu. Praktycznie nigdy nawet nie zwracamy tego modelu potem.

EDIT/Offtop: Jak widzę "getAll", a potem "getById", "getByName", "getByShoeSize" to mam wrażenie, że coś jest nie tak. Bo kiedy np. potrzebujesz całą tabelę wyciągnać?

0

Czy to przypadkiem nie jest swego typu overkill robić osobne klasy dla każdego zapytania? Czy znowu czegoś nie rozumiem? Ile masz, w sumie, klas w takim projekcie?

5

Nie mam tych klas zbyt dużo bo może ze 20? Tyle ile mam endpointów w API. Po prostu każdy endpoint dostaje dokładnie to czego potrzebuje, w takim formacie jaki chcę, bez nadmiarowych danych albo dziwnych zlepionych struktur.

Dzięki temu jak chcę zmienić strukturę danych w endpoincie A to to zmieniam, a nie zastanawiam się czy nie zepsuję endpointów B, C, D przez to.

Jak poszukasz info o takim podstawowym CQRS na jednej bazie to tam pewnie będzie to opisane lepiej.

0

No ok, myślę, że ma to sens. Mam jeszcze jedno pytanie - bo skoro mam zamiar używać EF + Dapper, to jak to jest w kwestii tworzenia bazy? Czy w takim przypadku też korzystam z code first? Dlaczego ten sposób jest tak popularny? Chodzi o napisanie raz klas i nie trzeba dłubać tabel w Management Studio?

0

Dapper nie gryzie się z EF. Dapper robi operacje czystym SQL na bazie a entity framework wymaga spójności modelu dbContextu z bazą. Możesz zastosować cose first bo jest po prostu łatwiejszy i spójny między dwoma systemami (apka i baza). Dłubanie tabel ma to ryzyko że zrobisz rename tabeli i EF tego nie załapie jeżeli nie wprowadzisz zmian w kodzie.

1

Dbcontext nie wymaga spojnosci z cala baza tylko z tym co ma zmapowane.mozesz mieć kilka dbcontextow w aplikacji i każdy mkze sobie malować po swojemu czesci bazy + jeden DbContext dla całej bazy do migracji.
Co ma dapper, poza wydajnością, czego nie można zrobić w EF?

1 użytkowników online, w tym zalogowanych: 0, gości: 1