Хабрахабр

ThinkingHome.Migrator — версионная миграция схемы базы данных на платформе .NET Core

Сегодня я выпустил новую версию ThinkingHome. Привет! NET Core.
Migrator — инструмента для версионной миграции схемы базы данных под платформу .

Вы уже можете пользоваться новеньким мигратором, а я расскажу, как он появился, почему у него номер версии 3. Пакеты опубликованы в NuGet, написана подробная документация. 0 (хотя это первый релиз) и зачем он нужен, когда есть EF Migrations и FluentMigrator. 0.

Как всё начиналось

NET разработчиком. 9 лет назад, в 2009 году я работал ASP. Мы искали инструмент, который делал бы это автоматически, и нашли проект Migrator. Когда мы релизили наш проект, специальный человек оставался на работе допоздна и, одновременно с обновлением файлов на сервере, руками выполнял SQL скрипты, обновляющие БД в проде. NET.

Каждая миграция содержит маленькую порцию изменений и имеет номер версии, в которую перейдет БД после её выполнения. Мигратор предлагал новую для того времени идею — задавать изменения БД в виде миграций. Особенно круто было то, что мигратор позволял для каждой миграции задать обратные изменения. Мигратор сам вел учет версий и выполнял нужные миграции в нужном порядке. Можно было при запуске мигратора задать версию, ниже текущей, и он автоматически откатил бы БД до этой версии, выполняя нужные миграции в обратном порядке.

[Migration(1)]
public class AddAddressTable : Migration
override public void Down() { Database.RemoveTable("Address"); }
}

Он не умел работать со схемами БД, отличными от схемы по умолчанию. В том миграторе было много ошибок. В результате мы с коллегами форкнули проект и чинили там баги. В некоторых случаях генерировал некорректные SQL запросы, а если указать ему несуществующий номер версии — впадал в бесконечный цикл.

Поэтому мы особенно не заморачивались с тем, чтобы наши изменения попали обратно в оригинальный проект — просто пилили свою копию и сами этим пользовались. GitHub.com с его форками и пулл реквестами тогда еще не было (код мигратора лежал на code.google.com). Потом я выложил код нашего мигратора на google code и написал статью на хабр. Со временем мы переписали бо́льшую часть проекта, а я стал его основным мэйнтейнером. Migrator. Так появился ECM7.

Заодно немного упростили API и покрыли всё автотестами. За время работы над мигратором мы почти полностью его переписали. В отличие от оригинального мигратора, было ощущение надежности и не было ощущения, что происходит непонятная магия. Лично мне очень нравилось пользоваться тем, что получилось.

Насколько я знаю, он использовался в довольно крупных компаниях. Как оказалось, наш мигратор нравился не только мне. Если наберете в поиске запрос "ecm7 migrator", то можете встретить в результатах статьи о нем, упоминания в резюме, описания использования в студенческих работах. Мне известно про ABBYY, БАРС Груп и concert.ru. Иногда мне приходили письма от незнакомых людей с вопросами или словами благодарности.

Его текущие возможности покрывали все задачи, которые у меня возникали и я не видел необходимости что-то доделывать. После 2012 года проект почти не развивался.

ThinkingHome.Migrator

NET Core. В прошлом году я начал работать над проектом на . Это как раз такая задача, для которой хорошо подходит мигратор. Там нужно было сделать возможность подключения плагинов, а у плагинов должна быть возможность создать себе нужную структуру БД, чтобы хранить там свои данные.

EF Migrations

К сожалению, почти сразу пришлось отказаться от идеи использовать их. Для работы с базой данных я использовал Entity Framework Core, поэтому первое, что я попробовал — это EF Migrations.

Шаг влево/шаг вправо — упираешься в ограничения. Миграции Entity Framework тащат в проект кучу зависимостей, а при запуске — делают какую-то особую магию. Это значит, что не получится хранить миграции внутри плагинов. Например, миграции Entity Framework почему-то обязательно должны быть в одной сборке с DbContext.

FluentMigrator

Самый продвинутый из них, судя по количеству загрузок в NuGet и звездочек на GitHub, оказался FluentMigrator. Когда стало ясно, что EF Migrations не подходят, я поискал решение в гугле и нашел несколько open source миграторов. Он умеет очень многое и у него очень удобный API. FM — очень хорош! Сначала я решил, что это то, то мне нужно, но позже обнаружилось несколько проблем.

Как я писал выше, мне нужно было использовать мигратор в модульном приложении. Главная проблема — FluentMigrator не умеет параллельно учитывать несколько последовательностей версий внутри одной БД. У FluentMigrator сквозная нумерация версий. Нужно, чтобы модули (плагины) можно было устанавливать и обновлять независимо друг от друга. Из-за этого нельзя выполнить/откатить из БД миграции одного плагина, не затронув структуру БД остальных плагинов.

FluentMigrator не хранит информацию о тэгах выполненных миграций. Я пробовал организовать нужное поведение при помощи тэгов, но это тоже не совсем то, что нужно. Это очень странно, учитывая, что точка входа для поиска миграций — именно сборка. Кроме того, тэги привязаны к миграциям, а не к сборкам. В принципе, наверно было можно таким образом сделать параллельный учет версий, но нужно написать над мигратором довольно сложную обертку.

Портировать ECM7.Migrator на .NET Core

В то время текущая версия . В начале этот вариант даже не рассматривал. 1 и её API был плохо совместим с . NET Core была — 1. Migrator. NET Framework, в котором работал ECM7. NET Core будет сложно и долго. Я был уверен, что портировать его на . Задача оказалась легче, чем я ожидал. Когда вариантов "взять готовое" не осталось, решил попробовать. Потребовались лишь небольшие правки. На удивление, всё заработало почти сразу. Так как логика мигратора была покрыта тестами, сразу были видны все места, которые сломались и я быстро починил их.

Не портировал адаптеры для Oracle (т. Сейчас я портировал адаптеры только для четырех СУБД: MS SQL Server, PostgreSQL, MySQL, SQLite. всё еще нет стабильного клиента под . к. он работает только под Windows и мне тупо негде его запускать) и Firebird (т.к. NET Core), MS SQL Server CE (т.к. В принципе, если нужно будет сделать провайдеры для этих или других СУБД — это довольно просто. он не очень популярный, портирую позже).

Настроен запуск тестов для каждой СУБД в Travis CI. Исходный код нового мигратора лежит на GitHub. NET Core Global Tool), которую можно легко установить из NuGet. Написана утилита командной строки (. Можно брать и пользоваться! Написана документация — я очень старался написать подробно и понятно и, кажется, так и получилось.

Немного про название...

Они работают на разных платформах и у них отличается API. У нового мигратора нет обратной совместимости со старым. Поэтому проект опубликован под другим названием.

Собственно, ECM7. Название выбрано по проекту ThinkingHome, для которого я портировал мигратор. Migrator тоже назван по проекту, над которым я работал в тот момент.

Если знаете такой — пишите в комментариях. Возможно, лучше было выбрать какое-то нейтральное название, но мне не пришло в голову хороших вариантов. Еще не поздно всё переименовать.

0. Номер версии указал 3. новый мигратор — логическое продолжение старого. 0, т.к.

Быстрый старт

Итак, давайте попробуем использовать мигратор.

Классы миграций наследуются от базового класса Migration из пакета ThinkingHome. Все изменения БД записываются в коде миграций — классов, написанных на языке программирования (например, на C#). Framework. Migrator. Внутри этих методов разработчик при помощи специального API описывает действия, которые нужно выполнить над БД. В них нужно переопределить методы базового класса: Apply (применить изменения) и Revert (откатить изменения).

Также класс миграции нужно пометить атрибутом [Migration] и указать версию, в которую перейдет БД после выполнения этих изменений.

Пример миграции

using ThinkingHome.Migrator.Framework; [Migration(12)]
public class MyTestMigration : Migration
{ public override void Apply() { // прямые изменения: создаем таблицу Database.AddTable("CustomerAddress", new Column("customerId", DbType.Int32, ColumnProperty.PrimaryKey), new Column("addressId", DbType.Int32, ColumnProperty.PrimaryKey)); } public override void Revert() { // обратные изменения: удаляем таблицу Database.RemoveTable("CustomerAddress"); // если откат изменений не нужен, то // метод Revert можно не переопределять }
}

Как запустить

После этого вы можете выполнить изменения БД с помощью консольной утилиты migrate-database. Миграции компилируются в файл .dll. Для начала, установите её из NuGet.

dotnet tool install -g thinkinghome.migrator.cli

Запустите migrate-database, указав нужный тип СУБД, строку подключения и путь к файлу .dll с миграциями.

migrate-database postgres "host=localhost;port=5432;database=migrations;" /path/to/migrations.dll

Запускаем через API

Например, вы можете написать приложение, которое при запуске само создает себе нужную структуру БД. Вы можете выполнять миграции через API из собственного приложения.

Migrator из NuGet и пакет с провайдером трансформации для нужной СУБД. Для этого подключите в свой проект пакет ThinkingHome. Migrator. После этого создайте экземпляр класса ThinkingHome. Migrator и вызовите его метод Migrate, передав в качестве параметра нужную версию БД.

var version = -1; // версия -1 означает последнюю доступную версию
var provider = "postgres";
var connectionString = "host=localhost;port=5432;database=migrations;";
var assembly = Assembly.LoadFrom("/path/to/migrations.dll"); using (var migrator = new Migrator(provider, connectionString, assembly))
{ migrator.Migrate(version);
}

Кстати, можете сравнить с примером запуска FluentMigrator.

Заключение

Кажется, получилось неплохо. Я старался сделать простой инструмент без зависимостей и сложной магии. Если вы используете . Проект давно не сырой, всё покрыто тестами, есть подробная документация на русском. 1, попробуйте новый мигратор. NET Core 2. Скорее всего, вам тоже понравится.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть