Нюансы при работе с EF миграциями
Данная статья не является инструкцией по работе с EF миграциями. Здесь не будет инфы о том, как их создавать. Здесь я собрал несколько скользких моментов и попытки их обойти. Давайте начнем!
Старт миграций при запуске приложения
Вам знаком следующий код?
context.Database.Migrate();
Если да, вероятнее всего вы накатываете миграции автоматически при старте проекта. Плохо это или хорошо, можете обсудить в комментариях. Я же в свою очередь хочу предостеречь вот от чего.
Когда вы в cmd, PS или в консоли диспетчера пакетов вызываете какую либо операцию, связанную с миграциями, эта операция включает в явном или неявном виде 2 параметра: проект и запускаемый проект. Проект - это сборка, в которую в конечном счете будут помещены миграции. А вот запускаемый проект - проект, выбранный запускаемым для данного решения (sln). При работе через консоль диспетчера пакетов вы этот параметр никогда не увидите.
Что это означает? А то, что ваш запускаемый проект при выполнении операции с миграциями будет собран (ну об этом вы знаете) и запущен. А это, в свою очередь, означает, что помимо всяких интеграционных штук, которые неожиданно для вас могут отработать, выполнение может дойти до кода, приведенного выше. К чему это может привести? К тому, что текущая операция с миграциями накатит предыдущую созданную вами миграцию. То есть, вы создаете миграцию, тут же, замечаете, что допустили ошибку в настройке сущности, пытаетесь ее удалить через Remove-Migration, но получаете от ворот поворот, потому что в момент запуска операции удаления миграции, она накатывается на базу. Вы, конечно же, выполняете роллбэк последней миграции и затем снова вызываете Remove-Migration. Но, угадайте, что произойдет?
Чтобы это побороть, могу подсказать 2 подхода:
Не использовать применение миграций при запуске проекта
Использовать в качестве запускаемого проекта для операций с миграциями отдельный консольный запускаемый проект.
Если есть идеи лучше, пишите в комментариях. С удовольствием обсужу с вами и приму к сведению.
Удаление миграций
В общем-то, удалять миграции я рекомендую только в двух случаях:
Миграция приводит к потере данных и пока код не добрался до прода, миграцию можно и нужно вычленить.
Миграция еще не слита в ветку, вы создали ее локально, но она не правильная.
Во втором случае можно удалить последнюю миграцию, использовав команду Remove-Migration. Если миграцию уже применили к базе, надо ее предварительно откатить. После выполнения Remove-Migration почистите мусор в файле проекта (csproj). Так же, если у вас всего одна миграция или несколько, но еще не закоммичены, быстрее будет откатить снапшот через Git (или вашу систему контроля версий) и удалить файлы миграций.
В данном случае универсальным решением будет откатить базу до удаляемой миграции, удалить все миграции после проблемной (вместе с ней). Мусор в csproj файле при этом чистить не надо.
Создание SQL миграций
Возможно, не все знают, но на основе разработческих миграций (тех, что создаются в коде, это майки их где-то так называли) можно создать SQL скрипты. Для этого есть команда Script-Migration. С ее помощью можно создать в т. ч. идемпотентные скрипты.
А начиная с версии EF Core 3.0 появилась команда Script-DbContext для создания миграций из контекста базы.
При развертывании, конечно, потребуется механизм для запуска этих скриптов, но зато это принесет плоды, когда в случаях возможной потери данных вы сможете добавить SQL прямо внутрь нужной миграции и вам не придется пересобирать проект.
Редактирование сущностей
Нут тут, казалось бы, все просто. Мы меняем что-либо в сущности, создаем миграцию, радуемся результату. Вот только результат может быть неожиданным, когда вам нужно удалить одно поле и создать другое того же типа. Мигратор при этом создаст команду для переименования столбца в БД. Все данные из удаляемого столбца, соответственно, перенесутся в новый. В данном случае можно создать 2 миграции: для удаления столбца и для создания нового. После этого, чтобы не маячили 2 миграции вместо одной, можно совместить их код Up и Down и последнюю удалить.
Заключение
В заключении хочу сказать, будьте внимательны к данным, проверяйте новые миграции, вдумывайтесь в них, не бойтесь их редактировать. А на всякие неочевидные грабли при работе с EF вы все равно наступите.