Migracja schematu bazy danych z DbUp

Wprowadzenie

Dwa ostatnie wpisy na blogu dotyczyły sposób migracji schematu bazy danych. Migracje w Entity Framework oraz Fluent Migrator charakteryzują się tym, że cały proces migracji jest zapisany w klasach za pomocą api, które udostępnia dana biblioteka. Ilość sqla, którą piszemy w tych migracjach jest minimalizowana i sprowadza się głównie do wykonywania jakiś specyficznych rzeczy – np. skopiowania danych z jednego miejsca w drugie. Natomiast dzisiejsza biblioteka (DbUp – https://dbup.github.io/) działa zupełnie inaczej. Pomaga ona wykonywać migracje, które są zapisane w plikach sql. Dlatego DbUp jest moim pierwszym wyborem w sytuacji, gdy w projekcie migracje są zdefiniowane w skryptach.

DbUp

Podobnie jak w przypadku Entity Framework oraz Fluent Migrator uruchamianie migracji organizuje w dedykowaną aplikacje konsolową. Dlatego w przykładzie na githubie (https://github.com/danielplawgo/DbUpExample) znajduje się tylko aplikacja konsolowa. Aby skorzystać z DbUp należy zainstalować pakiet https://www.nuget.org/packages/dbup z nugeta. W przykładzie dodałem również pakiety dla CommandLineParsera oraz NLoga, aby móc przekazać do aplikacji connection stringa oraz logować działanie migratora. Podobnie jak to było w poprzednich przykładach.

Jak wspomniałem wyżej wszystkie migracje będą zapisane w plikach sql. Tworze dla nich dedykowany katalog w projekcie. Również tutaj nazwy plików migracji zaczynają się od daty dodanie migracji. Aby później można było łatwiej analizować to co dzieje się z schematem bazy na przestrzeni czasu:

dbup solution explorer

Domyślnie DbUp wymaga, aby pliki sql z migracjami miały ustawiony Build Action na Embedded Resource w ustawieniach pliku:

dbup file properties

Jest to również jeden z częstych problemów z nieuruchamiającymi się migracjami w DbUp. Domyślnie nowy plik sql ma ustawiony Build Action na Content i trzeba pamiętać, aby zmienić to ręcznie.

Pierwsza migracja

W testowym projekcie posłużymy się tym samym przykładem co w poprzednich dwóch wpisach. Dzięki temu będziesz mógł porównać sposoby działania wszystkich trzech bibliotek. Dlatego w przykładzie pierwsza migracja dodaje do bazy danych tabele Products z trzema kolumnami oraz kilka rekordów:

Jak widać w tym przypadku całą zmianę schematu bazy danych mamy zapisaną w czystym sql. W C# zapiszemy jedynie sposób uruchamiania aplikacji, natomiast wszystko inne będzie w sql.

Uruchomienie migracji

Samo uruchomienie migracji nie jest mocno skomplikowane, jest to kilkanaście linii kodu. Podobnie jak inne biblioteki tego typu, DbUp korzysta z specjalnej tabeli, w której zapisuje informacje o wykonanych skryptach. Podczas uruchamiania sprawdza jakie są dostępne migracje w aplikacji i uruchamia tylko te, które nie zostały wcześniej uruchomione.

Warto pamiętać o tym, że DbUp rozpoznaje skrypty po ścieżce w projekcie oraz nazwie pliku. Na przykład pierwsza migracja będzie rozpoznana jako „DbUpExample.Migrator.Migrations.201810100538_AddProducts.sql”. Przez co musimy uważać z przenoszeniem migracji do innego folderu ponieważ DbUp może rozpoznać to jako zupełnie inną migracje.

Tak jak w poprzednich przykładach z migracjami, tak i w tym wykorzystałem klasę Options, która służy do parsowania parametrów za pomocą biblioteki CommandLineParser przekazywanych do aplikacji. Klasa Options zawiera tylko jeden parametr dla connection stringa:

Natomiast kod potrzeby do uruchomienia migracji wygląda tak:

Jak widać po sparsowaniu parametrów z wiersza poleceń w metodzie Migrate konfigurowany jest migrator z DbUp. Określamy w nim przede wszystkich connection stringa do bazy, którą chcemy zaktualizować. Do tego korzystamy z dostępnych providerów (wywołanie metody WithScriptsEmbeddedInAssembly), którzy określają skąd mają zostać załadowane pliki sql. W przykładzie są to dołączone pliki sql do projektu. DbUp udostępnia również inne sposoby ładowania plików – https://dbup.readthedocs.io/en/latest/more-info/script-providers/

DbUp wpiera również różne biblioteki do logowania działania aplikacji, takie jak nlog, log4net. Konfiguruje się je za pomocą metody LogToAutodetectedLog, która pod spodem korzysta z LibLog – https://github.com/damianh/LibLog

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 email, w których pokaże Ci w jaki sposób pracować efektywnej i szybciej w Visual Studio. Poznasz dodatkich, 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

Druga migracja, którą dodałem do projektu jest odpowiedzialna za utworzenie tabeli Categories, skopiowanie do niej nazwa kategorii oraz ustawienie CategoryId w tabeli Products. Sam sql migracji wygląda tak:

Wynik działania migratora

Poniżej znajduje się wynik działania migratora, który został uruchomiony dla pustej, dopiero co utworzonej bazy danych. Widać, że migrator wykrył, że żadna migracja nie została wykonana i wykonał obie migracje, które są dodane do aplikacji.

Filtrowanie migracji

Na koniec warto jeszcze wspomnieć o ciekawej funkcjonalności, którą daje DbUp i którą używałem w przykładzie. DbUp szukając migracji do wykonania umożliwia również filtrowanie znalezionych migracji. Robi się to poprzez przekazanie metody filtrującej (przyjmującej stringa z pełną nazwą migracji i zwracającą true lub false) do metody WithScriptsEmbeddedInAssembly, jak to jest zrobione w przykładzie powyżej.

Dzięki temu możemy używać jednej aplikacji do aktualizowania schematu różnych baz danych. Wystarczy na przykład dla każdego typu bazy danych utworzyć dedykowany katalog i do niego wrzucać skrypty. Później w metodzie filtrującej możemy na podstawie jakiegoś parametru przekazanego do aplikacji decykować, z którego katalogu mają być ładowane skrypty. Tak jak w przykładzie korzystając z metody StartWith klasy string.

Innym przykładem użycia takiego podejścia może być dodanie folderów z różnymi danymi testowymi, które również będzie filtrować metoda na podstawie parametrów przekazanych do aplikacji. Filtrowanie działa również w przypadku innych providerów.

Przykład

Tradycyjnie na githubie (https://github.com/danielplawgo/DbUpExample) znajduje się przykład, który użyłem podczas przygotowywania tego wpisu. Podobnie jak w przypadku pozostałych przykładów z migracjami schematu bazy danych, tak i w tym, aby uruchomić przykład musisz w ustawieniach projektu ustawić poprawny connection string do bazy, na której mają wykonać się migracje.

Zachęcam do pobawienia się przykładowym projektem.

Podsumowanie

DbUp jest kolejną biblioteką, którą możesz użyć do zarządzania schematem baz danych. Jak widać po przykładzie biblioteka przydaje się głównie wtedy, gdy planujemy w projekcie używać migracji zapisanych w czystym sql. Dlatego w pierwszej kolejności ją proponuje zespołom, które używają plików sql do zmiany schematu bazy danych, a nie korzystają jeszcze z żadnego narzędzia do automatyzowania uruchamia migracji i wszystko robią ręcznie.

Migracje z Entity Framework lub Fluent Migratora używam w sytuacji, gdy decydujemy się na tworzenie migracji w kodzie za pomocą dostępnego api, a nie w czystym sql.

Używałeś DbUp? Jakie są Twoje doświadczenia z tą bibliotekom? A może używasz innego narzędzia, które ma podobne funkcje jak DbUp? Proszę podziel się tym w komentarzu 🙂

1 thought on “Migracja schematu bazy danych z DbUp

Dodaj komentarz

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