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

Миграции в платформе Entity Framework в среде совместной работы

У нас есть несколько разработчиков, работающих над проектом, который использует Entity Framework 5.0. Каждый разработчик использует собственную локальную базу данных SQL 2012, чтобы он мог разрабатывать и тестировать, не мешая другим.

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

Итак, теперь рабочий процесс:

  • Разработчик изменяет свой datamodel
  • Использует add-migration <Name> и применяет его к своей базе данных с помощью update-database.
  • Проверяет изменение данных и перенос на Git.
  • Другой разработчик тянет, получает изменения и применяет его к своей базе данных.

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

У меня также было изменение в моем собственном datamodel, однако в конце update-database он дал мне предупреждение, что я все еще не был в курсе событий, поэтому я сделал add-migration <my migration>. Однако, когда он закрепил миграцию, он дал мне изменения всех миграций, которые я уже применил к базе данных. Итак: он попытался удалить столбцы, которые уже были удалены, попытался создать уже существующую таблицу и т.д.

Как это может быть? Мое предположение заключалось в том, что EF просто проверит таблицу _MigrationsHistory и выяснит, какие миграции еще не присутствовали в таблице, и применяйте их по порядку, упорядоченные по временной отметке той частью имени. Но, видимо, нет, потому что даже когда я отменяю свои собственные изменения, и у меня есть чистая среда, я все еще жалуюсь, что моя база данных не синхронизирована с моделью. Но я просто потянул эти изменения и применил их к моей базе данных. Он синхронизирован. Я вижу миграции, которые я только что применил в таблице _MigrationsHistory.

Единственное, о чем я могу думать, это то, что я добавил свойство в datamodel, который не привел бы к изменению базы данных (я добавил a List<X> в datamodel Y, где X - это множество из числа "один ко многим" Это не приведет к изменению базы данных, поскольку X уже имел внешний ключ для Y). Может ли это так? Если это так, это действительно хрупкое, потому что нет возможности добавить для него миграцию, поскольку нет изменений в базе данных, и я не уверен, как это исправить.

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

То, что я также пробовал, - это добавление миграций, которые я вытащил из своих сотрудников один за другим с помощью update-database -t:201211091112102_<migrationname>, но безрезультатно. Это все еще дает мне ошибочный эшафот.

Итак, что мы здесь делали неправильно, или EF просто не создан для совместной работы?

UPDATE

Я создал воспроизводимый тестовый пример, это немного длительный танец, хотя для имитации этого сценария с несколькими пользователями/несколькими базами данных.

https://github.com/JulianR/EfMigrationsTest/

Шаги для воспроизведения, когда у вас есть вышеупомянутый проект (эти шаги также присутствуют в коде):

  • add-migration Init
  • update-database (в базе данных 'TestDb')
  • Измените строку подключения, чтобы указать на TestDb1
  • update-database на TestDb1
  • Свойство Uncomment Foo on class Test
  • add-migration M1 для добавления свойства Foo в TestDb1
  • Комментарий снова Test.Foo
  • Измените строку подключения, чтобы указать на TestDb2
  • Исключить перенос M1 из проекта, чтобы он не применялся к TestDb2
  • Uncomment свойство Bar в классе Test
  • обновить базу данных, чтобы применить переход Init к TestDb2
  • add-migration M2, чтобы добавить свойство Bar в TestDb2
  • Изменить строку подключения, чтобы снова указать на исходный TestDb
  • Включить миграцию M1 в проект снова
  • Свойство Uncomment Foo on class Test
  • Uncomment property SomeInt в классе Test
  • обновление базы данных,
  • add-migration M3
  • update-database, получите ошибку, потому что M3 пытается добавить столбец Foo в базу данных TestDb, которая уже была добавлена ​​только миграцией M1.

Вышеупомянутое состоит в том, чтобы имитировать трех пользователей, в которых пользователь 1 вводит свою базу данных, а другие два используют его инициализацию для создания своей базы данных. Затем пользователь 2 и пользователь 3 сами вносят изменения в базу данных и добавляют их к исходному контролю вместе с миграциями, необходимыми для применения изменений. Затем пользователь 1 вытягивает изменения пользователя 2 и 3, в то время как пользователь 1 также внес изменения в базу данных. Затем пользователь 1 вызывает update-database, чтобы применить изменения пользователя 2 и 3. Затем он выравнивает свою собственную миграцию, которая затем ошибочно добавляет изменение от пользователя 2 или 3 к миграции подкладок, что вызывает ошибку при применении к базе данных пользователя 1.

4b9b3361

Ответ 1

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

Например, перед выполнением шага 17 (Update-Database) в вашем сценарии вы должны выполнить следующую команду

Add-Migration M2

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

Ответ 2

Вам нужно добавить пустую миграцию "слияния", которая будет reset моментальным снимком последней миграции в файле .resx. Сделайте это с помощью переключателя IgnoreChanges:

Add-Migration <migration name> -IgnoreChanges

Смотрите здесь для объяснения

Ответ 3

У нас схожие проблемы в нашей среде, вот что мы догадались до сих пор и как мы его обошли:

Если у вас есть изменения, которые вы применили (update-database), но не отмечены, а затем вы получаете изменения от другого разработчика, у которого нет ваших изменений, здесь ситуация перестает синхронизироваться. По нашему опыту, похоже, что метаданные, которые сохраняются для ваших собственных изменений, переполняются, написанные метаданными от другого разработчика, когда вы выполняете процесс базы данных обновлений. У другого разработчика нет ваших изменений, поэтому метаданные, которые будут сохранены, больше не являются реальным отражением вашей базы данных. Когда EF делает сравнение после этого, он "думает", что ваши изменения на самом деле снова являются новыми из-за изменения метаданных.

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

Ответ 4

Вариант 1: Добавить пустую миграцию слияния

  • Убедитесь, что любые ожидающие изменения модели в вашей локальной базе кода были записывается в миграцию. Этот шаг гарантирует, что вы не пропустите ни одного законные изменения, когда приходит время для создания пустого миграция.
  • Синхронизация с контролем источника.
  • Запустить обновленную базу данных для применения любые новые миграции, которые проверяют другие разработчики. ** Примечание: **** Если вы не получаете никаких предупреждений из базы данных обновлений тогда не было никаких новых миграций от других разработчиков и нет необходимости в дальнейшем слиянии.
  • Запустить Add-Migration  -IgnoreChanges (например, Add-Migration Merge -IgnoreChanges). Это создает миграцию со всеми метаданными (включая моментальный снимок текущей модели), но будет игнорировать любые изменения, которые он обнаруживает при сравнении текущей модели с моментальным снимком в последних переходах (это означает, что вы получаете пустой метод Up и Down).
  • Продолжайте разработку или отправьте исходный код (после запуска единичные тесты, конечно).

Вариант 2: обновление моментального снимка модели в последней миграции

  • Убедитесь, что любые ожидающие изменения модели в вашей локальной базе кода были записывается в миграцию. Этот шаг гарантирует, что вы не пропустите ни одного законные изменения, когда приходит время для создания пустого миграция.
  • Синхронизация с элементом управления источником.
  • Запустить Update-Database для применять любые новые миграции, которые проверяли другие разработчики. ** Примечание: **** Если вы не получаете никаких предупреждений из базы данных обновлений тогда не было никаких новых миграций от других разработчиков и нет необходимости в дальнейшем слиянии.
  • Запустить обновление базы данных -TargetMigration (в примере weve после этого будет Update-Database -TargetMigration AddRating). Эта роль возвращает базу данных в состояние второй миграция - эффективно "отменить последнюю миграцию из база данных. ** Примечание: **** Этот шаг необходимо сделать безопасным для редактирования метаданные миграции, поскольку метаданные также хранятся в __MigrationsHistoryTable базы данных. Вот почему вы должны используйте эту опцию только в том случае, если последняя миграция только в вашем локальном база кода. Если к другим базам данных применена последняя миграция также пришлось бы отбросить их назад и повторно применить последнюю миграцию к обновить метаданные.
  • Запустить Add-Migration  (в примере мы следовали за этим, было бы чем-то вроде Add-Migration 201311062215252_AddReaders). ** Примечание: **** Вам необходимо включить отметка времени, чтобы миграция знала, что вы хотите редактировать существующие миграция, а не строительство новых. Это обновит метаданные для последней миграции в соответствии с текущей моделью. Вы будете после завершения команды получите следующее предупреждение, но это именно то, что вы хотите." Только код конструктора для миграции '201311062215252_AddReaders' был переделан. Чтобы повторно всю миграцию, используйте параметр -Force. "
  • Запустить Update-Database для повторно примените последнюю миграцию с обновленными метаданными.
  • Продолжить разрабатывать или подчиняться контролю источника (после запуска вашего подразделения тесты, конечно).

В MSDN есть отличная статья. Пожалуйста, пройдите через него.

Код инфраструктуры Entity Framework Первичные миграции в командной среде

Ответ 6

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

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

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

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

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

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

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

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

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

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

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

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

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

Ответ 7

Решение, которое я смог придумать (по крайней мере, для 2 пользователей, не прошедших проверку на 3):

  • слияние миграции для синхронизации метаданных run-database-database (это должно завершиться неудачно), затем
  • добавить базу данных, а затем
  • удалить весь сгенерированный код в up() и down() методах

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

Ответ 8

Я согласен с @LavaEater. Суть проблемы, похоже, в том, что миграционные леса должны быть централизованы. Возможно, как часть какого-либо автоматизированного/интегрированного процесса сборки каждый раз, когда происходит нажатие? После этого полученные миграции могут быть извлечены из сервера членами команды.

Это означает, что их собственные сценарии миграции не должны быть перенесены на сервер.