EF w podejściu Database First vs Code First – co wybrać?

Czytając jeden z ostatnich postów u Maćka zauważyłem, że w komentarzach pojawiła się krótka wymiana opinii na temat wyboru “właściwego” podejścia w kontekście korzystania z Entity Framework. Sam miałem okazję używać każdego z podejść oferowanych przez EF i z biegiem czasu zacząłem dostrzegać plusy i minusy poszczególnych podejść. W tym poście postanowiłem zebrać moje przemyślenia na ten temat.

Entity Framework oferuje trzy podejścia:

  1. Code First – nie tworzymy schematu bazy wprost, zamiast tego definiujemy typy w C# odpowiadające modelowi danych, co w połączeniu z dodatkowymi adnotacjami i/lub Fluent API umożliwi EF wygenerowanie schematu bazy danych.
  2. Database First – tworzymy model bazy danych samodzielnie, następnie importujemy istniejącą bazę do modelu, na podstawie którego EF wygeneruje potrzebne klasy i zajmie się mapowaniem.
  3. Model First – tworzymy model bazy danych korzystając z designera, EF na podstawie gotowego modelu wygeneruje schemat bazy danych i odpowiadający mu zestaw klas.

Uważny czytelnik zauważy, że EF daje do dyspozycji trzy podejścia, a w tytule (świadomie) pominąłem jedno z nich- mianowicie Model First. Nie jest to pomyłka, ale świadomy zabieg, który wynika stąd, że mam do niego bardzo mieszane uczucia. Miałem okazję rozwijać projekty podążające tą drogą i zawsze podczas edycji modelu miałem wrażenie, że igram z szatanem i skończy się to płaczem, epitetami i siedzeniem po godzinach (a dlaczego, to może innym razem). Po takich doświadczeniach zwyczajnie nie zamierzam polecać go nikomu, biorąc pod uwagę, że EF oferuje dwie zadowalające alternatywy.

Podejście Code First

Z mojego punktu widzenia to podejście jest obecnie bardzo modne i ma powszechne zastosowanie w dużej liczbie projektów. Biorąc udział w pewnej liczbie projektów korzystających z tej metody udało mi się dojść do następujących wniosków:

Plusy
  1.  Dzięki Code First programista nie musi wiedzieć jakie są różnice w semantyce języka DDL w zależności od wybranego silnika bazy danych. Wystarczy, że zdefiniuje odpowiednie struktury w C# a EF załatwia resztę.
  2. Mamy do dyspozycji automatyczne migracje, co niesamowicie ułatwia aktualizowanie schematu bazy danych. Jesteśmy zwolnieni z pisania skryptów przyrostowych, migracje dbają o to za nas. Co więcej historia zmian jest automatycznie śledzona dzięki czemu bardzo szybko (i wygodnie) możemy cofnąć się do dowolnego stanu.
  3. Nie mamy w projekcie olbrzymiego pliku XML z definicją wszystkich typów i mapowań. Zdecydowanie łatwiej jest mergować zmiany modelu, co w przypadku pracy w dużym zespole może mieć duże znaczenie, ponieważ jak napisał Andiego w jednym z komentarzy u Maćka:

     (…) praca z nim w dużym zespole przy dużym projekcie to wejście do 9 kręgu piekieł.

  4. Jesteśmy uwolnieni od designera, który według mnie jest bardzo niewygodny (szczególnie przy pracy z dużymi bazami danych).
  5. Kod C# modelu jest dużo bardziej czytelny niż w przypadku plików generowanych przez EF w pozostałych podejściach. Każdy, kto zaglądał do takich plików ten wie o czym piszę.
Minusy
  1. Podejście Code First (przynajmniej na tą chwilę) nie wspiera mapowania funkcji. Jeżeli jest wysokie prawdopodobieństwo, że będziemy chcieli implementować funkcje po stronie bazy danych to w tym przypadku należy się zastanowić, czy jesteśmy w stanie zrezygnować z funkcji na rzecz procedur. Jeżeli nie, to lepiej wybrać skorzystać z podejścia Database First.
  2. Korzystanie z procedur do modyfikacji danych insert/update/delete teoretycznie zostało wprowadzone do EF od wersji 6. W praktyce nie zawsze jesteśmy w stanie dopasować to rozwiązanie do naszych potrzeb. Problem tkwi w tym, że właściwości klasy muszą odpowiadać zarówno kolumnom w bazie danych i parametrom wejściowym procedur. Czasem może się zdarzyć, że będziemy trzymali w bazie puste kolumny tylko po to, żeby EF był w stanie ustawić odpowiednie mapowanie. Kolejnym ograniczeniem jest fakt, że nie można mieszać bezpośredniego dostępu do tabeli z odwoływaniem przez procedury. Albo wszystkie operacje odbywają się bezpośrednio albo przez procedury.
  3. Używanie procedur w innym celu niż podany powyżej jest możliwe, ale wymaga zastosowania różnych obejść w zależności od scenariusza: Stored Procedures with Multiple Result Sets, Using Entity Framework Code First with Stored Procedures that have Output Parameters. Uważam to za duży minus dlatego, że programiści nie znający zbyt dobrze EF będą potrzebowali więcej czasu na zrozumienie zastosowanych rozwiązań.

 Podejście Database First

Miałem okazję rozwijać projekt oparty o to podejście i pracowało mi się całkiem dobrze. Pracowałem z tym podejściem dość długo i tutaj również doszedłem do pewnych wniosków:

Plusy
  1. Baza danych może być projektowana przez osobę nie znającą EF. Taki scenariusz może mieć miejsce w projekcie, w którym bazę projektuje architekt baz danych. Zazwyczaj taka osoba nie będzie znała EF.
  2. Odwrotnie niż w przypadku podejścia Code First tutaj mapowanie do funkcji, widoków i procedur jest wspierane i działa zadowalająco.
  3. Łatwiej wdrożyć w projekt programistów nie znających EF.
Minusy
  1. Czasem po zaktualizowaniu modelu nie zawsze wszystkie zmiany zostaną naniesione. Takie sytuacje niejednokrotnie mogą przyprawić o ból głowy osoby, które dopiero zaczynają przygodę z EF.
  2. Mergowanie zmian w sytuacji, gdy dwie osoby dokonały modyfikacji bazy danych równolegle bardzo często jest problematyczne.
  3. Nie mamy do dyspozycji migracji, samodzielnie musimy zarządzać aktualizacjami bazy danych.

Podsumowanie

Jak widać na postawione w tytule pytanie nie ma jednoznacznej odpowiedzi. Bardzo często spotykałem się z prostym podziałem: duża baza – Database First, mała – Code First. Według mnie rozmiar bazy danych nie ma żadnego znaczenia z punktu widzenia wyboru podejścia. Uważam, że przeważający wpływ ma specyfika samego schematu bazy danych. Każda z wybranych ścieżek ma plusy i szereg ograniczeń. Znając konsekwencje każdego z podejść zdecydowanie łatwiej podjąć trafną decyzję. Wybór jest o tyle istotny, że bardzo ciężko go zmienić w trakcie trwania projektu. Jasne, że dobre praktyki tworzenia kodu, odpowiednia abstrakcja i organizacja warstw powinny taką zmianę ułatwić, jednak w praktyce zmiana tak fundamentalnej decyzji może mieć rożne skutki i raczej jest niechętnie stosowana.

Zapraszam do dyskusji. Jestem przekonany, że temat nie został jeszcze wyczerpany.

9 comments on “EF w podejściu Database First vs Code First – co wybrać?
  1. Przy opisie Code First wziąłeś pod uwagę wszystko to co właśnie nie powinno być zagadnieniem. CodeFirst to sposób stworzenia aplikacji, której dostęp do danych będzie oparty na EF. CodeFirst to przede wszystkim sposób na pozwalający na skupieniu się na tym co najważniejsze, czyli na modelu biznesowym (!!!), a nie modelu danych.

    Innymi słowy pozwala zrobić to co od dawien dawna NHibernate. :)

    • W tym wpisie chciałem pokazać z czym się należy liczyć (wliczając w to komfort i utrudnienia techniczne) decydując się na każde z podejść. Z tej perspektywy wydaje mi się, że wskazałem istotne zagadnienia. Natomiast to zdanie: “CodeFirst to przede wszystkim sposób na pozwalający na skupieniu się na tym co najważniejsze, czyli na modelu biznesowym (!!!), a nie modelu danych.” jak najbardziej potraktowałbym jako dodatkowy plus na korzyść Code First.

  2. Bardzo lubię podejście Code First, jest jednak jeden problem przy tym podejściu – jeśli w zespole są osoby, które nigdy wcześniej nie miały z nim do czynienia to niestety, ale prawdopodobieństwo namieszania jest bardzo wysokie. Co do DB First – tutaj jedną z największych wad jest to, że rzeczywiście – usuwając bezpośrednio z bazy danych kolumnę, nasz model się nie zaktualizuje (przy update), co wymaga od nas ingerencji na modelu – i również przy tym podejściu można narobić niezłego bałaganu. Ogólnie moja opinia jest taka – i DB First i Code First są w porządku i to, którego użyjemy zależy od projektu/zespołu/naszego “widzimisię”.

    Bardzo dobry art!

    • Zgadzam się z Tobą. Prawdopodobieństwo namieszania przy Code First jest tym większe im więcej niestandardowych rozwiązań wykorzystamy. Generalnie, jak już wspomniałem, nie można powiedzieć, że jedno podejście złe a drugie dobre, każde ma swoje zastosowanie, trzeba jedynie znać konsekwencje (i pamiętać o nich).

      PS. Dzięki ;)

  3. Dla mnie podejście db first jest największą masakrą jaka mozna sobie zrobic w dużym projekcie. Albo model first, albo poco. Poco na,początku nie bylo, dziala dopiero od 4.1 natomiast db first to tylko i wyłącznie dla istniejących dużych baz danych, do których trzeba cos dopisać anie ma żadnego ORMa. Czemu? W db first nie ma a) relacji wiele do wielu na,poziomie konceptualnym b) dziedziczenia c) mest etc. Problemy związane z model first wynikają z nieumiejętnego zaprojektowania modelu, a nie z wad samego podejscia.

    Aż mnie szlag trafia jak czytam takie artykuły. Potem muszę się użerać z naprawianiem DALa i obsługi wszystkich asocjacji na poziomie kodu. Pomijając już problemy z aktualizacją bazy.

    • “Dla mnie podejście db first jest największą masakrą jaka mozna sobie zrobic w dużym projekcie.”

      Mam doświadczenie z podejściem z DB First w kilku dużych projektach (kilkadziesiąt tabel) i zupełnie nie mogę się zgodzić, że to “największa masakra”. Według mnie problem z podejściem Model First wynika przede wszystkim z tego, że człowiek jest skazany na pracę z designerem. Dodatkową “masakrą” jest mergowanie zmian od kilku osób na raz.

      “Aż mnie szlag trafia jak czytam takie artykuły. Potem muszę się użerać z naprawianiem DALa i obsługi wszystkich asocjacji na poziomie kodu. Pomijając już problemy z aktualizacją bazy.”

      Mnie dla odmiany szlag trafia jak muszę się użerać z naprawianiem modelu w designerze albo mergować plik edmx ;).

  4. W db first nie ma a) relacji wiele do wielu na,poziomie konceptualnym b) dziedziczenia

    Jak to nie ma? Wystarczy po utworzeniu ustawić odpowiednie relacje, czy to wiele do wielu, czy dziedziczenie. Po takim działaniu mamy model, który uwzględnia te aspekty, a kreator aktualizuje nasz model na podstawie bazy danych już z uwzględnieniem tych wprowadzonych zmian.

    • Jeśli mnie pamięć nie myli, jeżeli w bazie jest “czysta” tabela wiążąca id dwóch tabel, to EF automatycznie utworzy relację wiele-do-wielu.

Reply to Kryszał × Cancel reply

Your email address will not be published. Required fields are marked with a grey bar.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

Current ye@r *