Migracja schematu bazy danych z Fluent Migratora

Wprowadzenie

W ubiegłym tygodniu pokazałem Ci, w jaki sposób migrować schemat bazy w Entity Framework (zachęcam do przeczytania najpierw tamtego wpisu). W tym wpisie pokażę Ci inną bibliotekę, której możesz użyć do migracji schematu bazy, w momencie gdy z jakiegoś powodu nie możesz użyć Entity Framework. Biblioteka nazywa się Fluent Migrator (https://fluentmigrator.github.io/) i w swoim działaniu jest bardzo podobna do mechanizmu migracji z Entity Framework. Największą różnicą miedzy tymi narzędziami jest to, że w Fluent Migratorze musimy sami napisać całą migrację – a nie tak, jak w Entity Framework, gdzie migracja jest generowana na podstawie zmian w modelu.

Fluent Migrator

Migracje w Fluent Migratorze są zorganizowane w podobny sposób jak w Entity Framework – czyli dodajemy nową klasę dla każdej migracji. Klasa migracji musi dziedziczyć po klasie Migration i implementować dwie metody: Up oraz Down. Pierwsza metoda podnosi schemat bazy danych, druga natomiast służy do cofania zmian.

Fluent Migrator udostępnia wiele metod, za pomocą których możemy definiować schemat bazy danych. Nie musimy wszystkiego pisać w sqlu i korzystamy z dostarczonego fluent api (stąd nazwa biblioteki). Plusem takiego podejścia jest to, że Fluent Migrator generuje odpowiedniego sqla dla każdego silnika baz danych, jaki wspiera. Jak zobaczysz później – trochę tego jest.

Migracja

Najlepiej od razu zobaczyć pierwszą migrację w akcji. Będzie to ten sam przykład, co w poprzednim wpisie. Poniżej migracja, która dodaje tabelę Products z trzema kolumnami:

Na pierwszy rzut oka widać, że powyższa migracja jest podobna do migracji wygenerowanych przez Entity Framework. Również korzystamy z dostępnych metod, za pomocą których określamy zmiany w strukturze bazy danych. Na podstawie tych metod Fluent Migrator wygeneruje później odpowiedniego SQLa, który zostanie wykonany na bazie danych.

W migracji warto zwrócić uwagę na dwie rzeczy. Po pierwsze widać, że klasa dziedziczy po klasie Migration i nadpisuje dwie metody Up oraz Down.

Po drugie migracja jest udekorowana atrybutem Migration z dziwnym numerem. Numer ten określa wersję migracji. W przypadku Fluent Migratora jest to liczba typu long. Biblioteka na podstawie tej liczby określa później między innymi kolejność wykonywania migracji. Osobiście w określeniu wersji migracji stosuję datę dodania migracji – rok-miesiąc-dzień-godzina-minuta (oczywiście bez łącznika). Dzięki temu dużo łatwiej pracuje mi się na migracjach w różnych branchach, niż gdybym stosował kolejne liczby naturalne. Z drugiej strony przedział minutowy jest na tyle mały, że szansa dodania dwóch migracji z tą samą wersją przez dwie różne osoby jest bardzo mała.

Wersję migracji dodaję również do nazwy plików z migracjami, podobnie jak to robi Entity Framework. Dzięki temu łatwiej później widać kolejność migracji w Solution Explorer:

fluent migrator solution explorer

Uruchomienie migracji

Podobnie jak w przypadku migracji w Entity Framework, również w przypadku Fluent Migrator do uruchamiania migracji wykorzystuje dedykowaną aplikację konsolową. W tym przypadku również klasy migracji znajdują się w projekcie migratora (co widać na zrzucie ekranu powyżej).

Aby utworzyć migratora, należy w pierwszej kolejności zainstalować pakiet FluentMigrator.Runner. Zainstaluje on wszystkie inne niezbędne pakiety. Pakiet ten ma również jeden minus. Instaluje on runnery dla wszystkich wspieranych przez Fluent Migrator baz danych. Ale z racji, że jest to oddzielna aplikacja, nie jest to dla mnie duży problem.

Testowy projekt korzysta z CommandLineParser do parsowania parametrów aplikacji oraz nloga do obsług logów.

Tym razem obiekt parametrów rozszerzyłem o dodatkowy parametr (v-version), który umożliwia przekazanie numeru wersji, do której trzeba cofnąć schemat bazy danych:

Natomiast sama klasa Program z uruchomieniem migracji wygląda tak:

Metoda CreateServices jest odpowiedzialna za skonfigurowanie runnera migracji. W niej określamy między innymi to, dla jakiego silnika mają zostać wygenerowane sqle, jakiego użyć connection stringa, czy gdzie znajdują się migracje.

Metoda UpdateDatabase wykonuje natomiast aktualizacje lub cofnięcie schematu bazy danych – w zależności od parametru version przekazanego do aplikacji.

Jak widać, kod nie jest jakoś bardzo mocno skomplikowany. Można go rozbudować o jakieś dodatkowe funkcjonalności, których potrzebowalibyśmy w systemie – na przykład dodawanie testowych danych.

Przykłady uruchomienia aplikacji z poziomu wiersza poleceń:

Darmowy kurs Visual Studio

Pracując z setkami programistów, zauważyłem, że większość osób nie pracuje efektywnie w Visual Studio. W skrajnych przypadkach korzystali z kopiowania z wykorzystaniem menu Edit. Wiem, że to dziwne, ale naprawdę niektórzy tak pracują. Dlatego postanowiłem stworzyć kurs Visual Studio – aby pomóc koleżankom i kolegom w efektywniejszej pracy.

Przygotowałem 20 lekcji e-mail, w których pokażę Ci, w jaki sposób pracować efektywniej i szybciej w Visual Studio. Poznasz dodatki, bez których nie wyobrażam sobie pracy w tym IDE.

Po więcej informacji zapraszam na dedykowaną stronę kursu: Darmowy Kurs Visual Studio.

Quiz C#

Ostatnio przygotowałem również quiz C#, w którym możesz sprawdzić swoją wiedzę. Podejmiesz wyzwanie?

Druga migracja

Jak widać na powyższym zrzucie ekranu, testowy przykład posiada dwie migracje. Podobnie jak w poprzednim wpisie druga migracja jest odpowiedzialna za utworzenie dedykowanej tabeli dla kategorii, przekopiowanie danych z kolumny Category z tabeli Products oraz ustawienie ID kategorii (kolumna CategoryId) w tabeli z produktami. Sama migracja wygląda tak:

Dalej większość kodu migracji to korzystanie z dostępnego API. Jedynie samo skopiowanie danych jest zrealizowane przez użycie czystego SQL-a.

Wygenerowany SQL

Warto przejrzeć jeszcze, jaki sql zostanie wygenerowany przez Fluent Migratora. Tutaj wspomnę o kolejnej różnicy między Entity Framework a Fluent Migratorem. Entity Framework jest w stanie utworzyć nam bazę danych, w przypadku gdy jej nie ma. Natomiast Fluent Migrator zakłada, że jest już ona utworzona. Dlatego przed uruchomieniem testowej aplikacji upewnij się, czy testowa baza istnieje.

Na listingu poniżej znajduje się log z działania aplikacji, która została uruchomiona na pustej (dopiero co utworzonej) bazie danych:

Biblioteka w pierwszych kilku zapytaniach sqla tworzy specjalną tabelę (VersionInfo), do której później zapisuje informacje o wykonanych migracjach. Dzięki temu wie, jakie migracje zostały wykonane na bazie i jakie jeszcze trzeba wykonać.

Kolejne zapytania są już właściwymi zapytaniami z migracji. Polecam przejrzeć wykonane zapytania i porównać to z tym, jak samemu by się je napisało.

Entity Framework vs Fluent Migrator

Na koniec warto zastanowić się, z której biblioteki skorzystać. Niewątpliwą zaletą Entity Framework jest to, że sama biblioteka generuje większość kodu migracji na podstawie zmian modelu. My jako programiści musimy jedynie dodać pojedyncze sqle, które są odpowiedzialne za skopiowanie danych. W przypadku Fluent Migratora niestety musimy wszystko napisać sami.

Dlatego w moim przypadku w pierwszej kolejności staram się wybrać migracje w Entity Framework, gdy mam taką możliwość. Jeśli z jakichś powodów nie mogę w projekcie skorzystać z Entity Framework (np. jest użyty innym ORM np. NHibernate), wtedy korzystam z Fluent Migratora.

Przykład

Na githubie (https://github.com/danielplawgo/FluentMigratorExample) znajduje się przykład do tego wpisu. Praktycznie cały kod znajduje się w projekcie FluentMigratorExample.Migrator, który należy uruchomić. We właściwościach projektu w zakładce Debug znajduje się connection string, który domyślnie wykorzystuje aplikację, gdy jest uruchomiona z poziomu Visual Studio. Aby aplikacja się uruchomiła poprawnie, należy upewnić się, że baza określona przez connection string istnieje, lub zmienić go na właściwą bazę danych.

Gorąco zachęcam do pobrania przykładu i sprawdzenia Fluent Migratora w praktyce.

Podsumowanie

W tym wpisie pokazałem Ci inną bibliotekę, którą możesz wykorzystać do tworzenie migracji. Fluent Migrator, o którym mowa, jest bardzo podobny w swym działaniu do mechanizmu migracji w Entity Framework. Dlatego jest to mój pierwszy wybór w momencie, gdy nie mogę skorzystać z Entity Framework w swoim projekcie.

Za tydzień kolejna biblioteka (DbUp), która tym razem będzie działać nieco inaczej. Przydaje się ona, gdy migracje mamy zapisane w wielu plikach sql. Ale o tym już w kolejnym wpisie.

1 thought on “Migracja schematu bazy danych z Fluent Migratora

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *