Подтвердить что ты не робот

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

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

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

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

Обновление

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

4b9b3361

Ответ 1

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

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

add-migration [the_migration_to_rescaffold_metadata_for]

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

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

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

  • Миграция A из ветки Изменение foo на boolean (0 автоматически станет false и > 0 станет истинным)

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

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

Ответ 2

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

До тех пор, пока команда ADO.NET не предложит некоторые рекомендации, я бы выполнил простой принцип:

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

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

Edit:

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

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

Ответ 3

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

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

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

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

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

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

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

  • Объединить ветки в git

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

  • Удалите локальную миграцию (MyMigration)

  • Запуск: ОБНОВЛЕНИЕ-БАЗА ДАННЫХ. Это применит все новые миграции, выполненные в других ветвях.

  • Запуск: ADM-MIGRATION MyMigration. Это приведет к повторной генерации локальной миграции на основе текущего состояния базы данных, например git -rebase.

  • Запуск: ОБНОВЛЕНИЕ-БАЗА ДАННЫХ. Обновите базу данных с помощью локальной миграции.

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

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

Ответ 4

Роуэн Миллер сделала отличное видео по этой теме на канале 9: Миграции - Командная окружение. Это относится к инфраструктуре сущности 6.

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

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

Решение:

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

Add-Migration NameOfMigration -IgnoreChanges

Затем команда UpdateDatabase будет успешной.


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

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

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

Ответ 5

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

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

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

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

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

Вы добавляете имя FirstName и LastName.

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

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

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

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

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

Должен работать еще немного, это мои мысли об этом, по крайней мере.

Ответ 6

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

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

Ответ 7

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

  • Отдел развития - Локальное развитие
  • Основной филиал - слияние изменений с веткой разработки и развертывание в моей промежуточной среде (веб-сайт Azure и база данных SQL)
  • Отключить ветку - объединить изменения с основного и развернуть в производственную среду (другой сайт Azure и базу данных SQL)

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

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

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

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

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

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