У нас есть несколько разработчиков, работающих над проектом, который использует 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.