Как управлять миграциями в проекте с несколькими ветвями?

У меня есть ASP.NET проект MVC3, который использует Entity Framework 4.3 с подходом code-first. Я использую миграции для обновления базы данных.

проект находится под контролем и у меня есть ряд филиалов. Я только что понял, что будет проблема, когда я захочу объединить одну из своих ветвей в мастера. Поскольку я создал migration-files в обеих ветвях, при слиянии будут перекрываться миграции, что, вероятно, вызовет рознь.

есть ли хороший способ управления миграциями в проекте с несколькими ветвями?

обновление

одним из способов было бы объединить, затем удалить все файлы миграции, созданные в то время как ветви были отдельными, а затем создать один новый файл миграции, который содержит все изменения с момента создания ветви до ее объединения обратно. Это будет работать для dev-среды, где вы можете сбросить базу данных и заново построить ее со всеми файл миграции. Тогда проблема будет в живой среде. Поскольку вы не можете вернуться к моменту создания ветви без риска потери данных, при попытке использовать новый файл миграции для обновления живой базы данных возникнет конфликт.

7 ответов


Я думаю, что принятый ответ неверен. Есть гораздо лучшее решение для обработки конфликтов слияния миграции entity framework по аналогичному вопросу.

все, что вам нужно сделать после слияния, это повторно собрать метаданные миграции в целевой ветви. То есть вы не rescaffold вверх/вниз код, просто государство в файлов resx-файл.

add-migration [the_migration_to_rescaffold_metadata_for]

эта процедура завершится неудачей, если другая миграция в слиянии изменила база данных таким образом, что миграция больше не выполняется или дает неожиданный результат. При этом я считаю, что это очень редкий случай, поскольку большинство миграций должны быть автоматически сгенерированы или, по крайней мере, не зависеть от других таблиц, которые также не изменяются в самой миграции. Очень незначительный вопрос, но один, чтобы быть в курсе.

одним из таких случаев может быть fxp (я не мог придумать лучшего примера)

  • столбец foo является int, а строки содержат [0, 1, 2]

  • миграция A из ветви a изменение foo в boolean (0 автоматически станет false и > 0 станет правдой)

  • миграция B из ветви B измените foo на string. Он ожидает, что это будет int, но это логическое значение, хотя миграция будет успешной. Данные будут потеряны, так как при создании миграции B строки будут содержать ["0", "1", "2"]. При миграции измененного столбца в boolean (и сделал это успешно и с ожидаемым результатом) строки теперь будут содержать ["0", "1", "1"] вместо этого и миграция B будет иметь другой конечный результат, чем тот, который наблюдался в ветви B.

вероятно, есть больше крайних случаев, когда все может пойти не так с решением. Но если migrations up / down code не зависит от вещей, измененных другой миграцией в слиянии, он должен хорошо работать, чтобы просто обновлять метаданные в миграциях.


слияние миграций-это ручная задача IMHO. Часть кода миграции генерируется автоматически, и мы обычно не объединяем автоматически генерируемый код-вместо этого мы снова запускаем автогенерацию после слияния.

до ADO.NET команда дает некоторые рекомендации я бы следовал простому принципу:

  • перед слиянием верните базу данных master к версии, используемой до ветвления
  • объединить свои филиалы
  • исключить созданные классы миграции после ветвления от объединенной сборки
  • добавьте новую миграцию для объединенной базы кода, которая перенесет вашу базу данных в состояние до ветвления в состояние после слияния ветвей
  • если исключенные классы миграции содержат некоторые настройки, объедините их с новым классом миграции
  • выполнить миграцию, чтобы перенести базу данных в текущую объединенную версию

Если ваши ветви содержат несколько шагов миграции (версия), вы потеряете их и вы закончите с двумя версиями-до ветвления и после слияния.

изменить:

Он не будет работать в реальной среде. Проблема здесь будет заключаться в самом процессе развития. Если у вас есть живая среда, Вы должны сохранить ее ветку нетронутой (за исключением незначительных исправлений ошибок). Если вы продолжаете разработку в этой ветви с производственным развертыванием и в то же время создаете другую версию в отдельной ветви без непрерывной интеграции (= непрерывное слияние изменения обратно в основную ветку для интеграции вашей новой разработки с основной базой кода) у вас большая проблема. Я думаю, что миграции в целом не могут справиться с этим.

единственным вариантом в таком случае, вероятно, будет удаление всех миграций из Объединенного решения и удаление MigrationHistory таблицы из базы данных. Затем вы можете снова включить миграции в проекте и добавить начальную миграцию, чтобы использовать текущую базу данных в качестве отправной точки = нет пути назад к предыдущей версии, потому что нет информация о предыдущих миграциях будет существовать.


Edit: мой коллега обнаружил, что легче сделать это, я оставил свой первоначальный ответ внизу для полноты.

(очень важно) миграции в живой среде не должны конфликтовать с миграциями в вашей текущей ветви, иначе вам нужно повторить все миграции и разрешить конфликты изменения модели данных вручную.

  1. восстановление базы данных разработки с данными живой среды
  2. run update-database, Он должен работать миграции из вашей ветви и жалуются на " неспособность обновить базу данных, чтобы соответствовать текущей модели бла-бла..'
  3. run add-migration MergeBranchBToMaster -ignoreChanges, это создаст пустую миграцию.
  4. run update-database снова
  5. изменений

магия в шаге 3 в основном говорит EF заткнуться о несоответствующих моделях, поэтому будьте очень уверены, что ваши миграции не конфликтуют с ними в живой среде. Если это так, вы всегда можете создавать сценарии SQL для нажатие отсутствующих миграций (что на самом деле является предпочтительным методом).

Оригинальный Ответ

Я нашел довольно прямое решение, основанное на ответе @ Ladislav Mrnka. Это будет работать с живой средой[1], вам просто нужно быть осторожным, чтобы не изменить развернутые миграции.

  1. перед слиянием обратите внимание на добавленную миграцию (MyMigration), и его предыдущая миграция (BaseMigration)

  2. объединить ветви в git

  3. Откройте консоль диспетчера пакетов и запустите: UPDATE-DATABASE-TargetMigration:BaseMigration. Это вернет вашу базу данных в состояние до применения любой из конфликтных миграций

  4. удалить локальную миграцию (MyMigration)

  5. Run: UPDATE-база данных. Это позволит применить все новые миграции в другие ветви.

  6. Run: ADD-миграция MyMigration. Это будет повторно генерировать локальную миграцию на основе текущего состояния базы данных, например git-rebase.

  7. Run: UPDATE-база данных. Обновите базу данных с помощью локальной миграции.

Это также работает, если у вас несколько локальных миграций, но объединить их все в один.

[1] работая с живой средой, я имею в виду, что сгенерированная миграция может быть применен к живой среде, которая уже может иметь некоторые / все миграции других ветвей. Сами шаги предназначены исключительно для целей развития.


Роуэн Миллер сделал отличное видео на эту тему на канале 9:Миграция Сред. Это относится к entity framework 6.

он описывает сценарий, когда первый разработчик A и B работают над одной и той же моделью, а A сначала проверяет. Теперь разработчик B должен иметь дело с проблемами, которые у него есть, когда он получает последнюю версию от A.

это по существу то же самое, что конфликты между различными ветвями, потому что общая проблема слияние изменений миграции выполняется одновременно, но эффективно с другим исходным состоянием модели.

решение:

  • при разрешении конфликтов системы управления версиями разработчик B должен принять как изменения от себя, так и от разработчика A.
  • An UpdateDatabase команда разработчика B все равно не удастся в это время (сообщение об ошибке: " не удалось обновить базу данных в соответствии с текущей моделью, потому что есть ожидающие изменения...")
  • разработчик B должен создать "пустую миграцию", используя :

Add-Migration NameOfMigration -IgnoreChanges

тут получится.


источник проблемы

источником ошибки, возникающей при обновлении базы данных, является то, что EF хранит снимок модели, на которую ссылается миграция, в файле resx в рамках миграции файл.

в этом случае разработчики B снимок "текущей модели" не является правильным после получения / слияния изменений, внесенных разработчиком A.


Я вложил в это некоторые мысли, и я надеюсь, что внесу свой вклад в различные мнения и практики, представленные здесь.

рассмотрим, что на самом деле представляют ваши локальные миграции. При работе локально с базой данных dev я использую миграции для обновления базы данных наиболее удобным способом при добавлении столбцов и т. д. В таблицы, добавлении новых объектов и т. д.

Итак, Add-Migration checks мой текущая модель (назовем ее моделью b) против мой предыдущая модель (Модель a) и генерирует миграцию, чтобы перейти от a => b в базе данных.

для меня очень мало смысла пытаться объединить мой миграция С кем-нибудь elses миграции,если у каждого действительно есть своя база данных, и тогда в организации существуют какие-то серверы баз данных stage / test / dev / production. Все зависит от того, как команда настроена, но имеет смысл изолировать друг друга от изменений что другие люди делают, если вы хотите действительно работать в распределенном режиме.

Ну, если вы работаете распределенно и у вас есть какой-то объект, человек, например, над которым вы работаете. По какой-то причине многие другие люди также работают над этим. Итак, вы добавляете и удаляете свойства Person по мере необходимости для вашей конкретной истории в спринте (мы все здесь работаем agile, не так ли?), как номер социального страхования, который вы сначала превратили в целое число, потому что вы не так ярки, а затем в строку так далее.

вы добавляете имя и фамилию.

вы закончили, и у вас есть десять странных вверх и вниз миграций (вы, вероятно, удалили некоторые из них во время работы, так как они были просто дерьмом), и вы получаете некоторые изменения из центрального репозитория Git. Круто. Вашему коллеге Бобу тоже нужны были имена, может, вам стоило поговорить друг с другом?

в любом случае, он добавил NameFirst и NameLast, я думаю... так что ты делаешь? Ну, слияние, реструктуризация, смена тем в нем больше имена вменяемым... как FirstName и LastName, вы запускаете свои тесты и проверяете его код, а затем нажимаете на центральный.

а как насчет перелетов? Ну, теперь было бы время сделать миграцию, перемещающую центральное РЕПО, или ветвь "тест", более конкретно, содержать приятную небольшую миграцию из его модель a = > модель b. Эта миграция будет одна и только одна миграция, а не десять странных.

ты понимаешь, к чему я клоню? Мы работаем с хорошими маленькие pocos и их сравнения составляют фактические миграции. Итак, мы вообще не должны объединять миграции, на мой взгляд, у нас должны быть миграции на ветку или что-то в этом роде.

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

нужно еще поработать, по крайней мере, так я думаю об этом.


рассмотрите возможность использования другой библиотеки миграции, которая не вызывает этих конфликтов, например FluentMigrator или Migrator.NET.

Я не думаю, что миграции EF действительно готовы к общему использованию с ветвями и слияниями-это много работы и слишком легко совершать неприятные ошибки.


Я думаю, что @LavaEater говорит много смысла. Я реализую стратегию ветвления (разработка, Main, Release) и согласовываю ее со средами в процессе разработки, QA и release.

  • филиал развития-Местное развитие
  • основная ветвь-слияние изменений из ветви разработки и развертывание в моей промежуточной среде (веб-сайт Azure и база данных SQL)
  • Release branch-слияние изменений из Main и развертывание в Производственная среда (другой веб-сайт Azure и база данных SQL)

Я столкнулся с проблемой, рассмотренной выше, и, на мой взгляд, осложнения вокруг миграции и потенциальные обходные пути вносят большой риск в процесс выпуска. Выполнение независимых миграций в Development, Main и Release эффективно означает, что схема I, включенная в сборку в Dev, не является схемой, которая переходит в QA на промежуточной стадии, и схемой, на которой QA подписывается Staging-это не схема, развернутая для Live (если я не следую одному из предлагаемых решений, которое, я уверен, будет работать, но может быть подвержено ошибкам).

to echo @LavaEater - какова реальная польза, которую я получаю от кода EF в первую очередь? Лично я думаю, что это легкость, с которой я могу создать схему из кода (и потенциально настроить автоматически генерируемые миграции, если я хочу). После этого миграции являются осложнением того, что должно быть простым развертыванием процесс.

мое текущее мышление состоит в том, чтобы сначала использовать код для генерации миграций в разработке, а затем: -

  • опция A)-используйте Update-Database-script для создания сценария изменений схемы и помещайте их под контроль источника. Существует еще некоторый потенциал для конфликтов, если 2 человека изменяют одну и ту же модель, но я думаю, что это легче управлять.

  • опция B) - Используйте что-то вроде SQL Compare для генерации изменения схемы файлы сценариев. Это потенциально более гибко и прозрачно, поскольку мне нравится видеть, какие именно изменения схемы я применяю к своей производственной базе данных (назовите меня параноиком).

Я что-то пропустила? Я предполагаю, что будет некоторая конфигурация для отключения первых миграций кода в основной и выпускной ветвях (при условии, что БД будет создана и обновлена скриптами). Кроме того, это кажется безопасным решением, но я бы оценил 2-е мнение.