Ошибка обновления базы данных из-за ожидающих изменений, но Add-Migration создает дублирующую миграцию
Я работаю с Entity Framework 5.0 First First Migrations, и у меня возникла проблема с запуском Update-Database. В нем говорится, что ожидаются изменения модели; но он должен быть обновленным, поэтому я запускаю
Add-Migration SomeMigrationName
и он создает файл... однако он создает файл, который по сути является одним и тем же дублированием предыдущей миграции (если я снова пытаюсь обновить базу данных в этом файле, у него возникают проблемы, связанные с попыткой удалить несуществующее ограничение). Кроме того, мне удалось подтвердить, что "первоначальная" миграция была выполнена на основе как модели данных в БД, так и из-за наличия записи в таблице __MigrationHistory!
Если я удалю всю базу данных и снова запустил все миграции, автоматически или вручную, у меня такая же проблема.
"Первоначальный" файл миграции, который у меня был, следующий:
public partial class RenameLinkColumns : DbMigration
{
public override void Up()
{
DropForeignKey("dbo.Listing", "OfferedByUserId", "dbo.User");
DropIndex("dbo.Listing", new[] { "OfferedByUserId" });
AddColumn("dbo.Listing", "ListedByUserId", c => c.Int(nullable: false));
AddForeignKey("dbo.Listing", "ListedByUserId", "dbo.User", "UserId", cascadeDelete: true);
CreateIndex("dbo.Listing", "ListedByUserId");
DropColumn("dbo.Listing", "OfferedByUserId");
}
public override void Down()
{
AddColumn("dbo.Listing", "OfferedByUserId", c => c.Int(nullable: false));
DropIndex("dbo.Listing", new[] { "ListedByUserId" });
DropForeignKey("dbo.Listing", "ListedByUserId", "dbo.User");
DropColumn("dbo.Listing", "ListedByUserId");
CreateIndex("dbo.Listing", "OfferedByUserId");
AddForeignKey("dbo.Listing", "OfferedByUserId", "dbo.User", "UserId", cascadeDelete: true);
}
}
Когда я снова запустил эту Add-Migration, методы Up/Down в этом файле точно такие же.
Я очень впечатлен тем, что миграция правильно распознала, что я переименовал столбец ForeignKey; но это то, что заставляет это задыхаться?
Кажется, что есть обход: я удалил базу данных и все файлы миграции и создал новую "начальную" миграцию, но я бы предпочел не делать этого, если это возможно.
Обновление: Это была не последняя миграция, вызвавшая эту проблему, но проблема возникла после слияния (я работаю один, но я имитирую работу команды в ветких, чтобы узнать больше о git тоже), и пытается получить базу данных в шаге с слиянием. Возможно, это произошло из-за переноса миграции в определенном порядке после слияния - хотя отмечено, миграция действительно работала, как ожидалось, в том порядке, в котором они выполнялись, когда я дал им пустую БД.
Кроме того, эта первоначальная миграция требует ручной настройки, когда в таблицы были данные, поскольку данные необходимо скопировать из старого в новый столбец. Тем не менее, я протестировал этот файл с моими ручными изменениями и без него в этом файле и по-прежнему сталкивался с отмеченным поведением.
Ответы
Ответ 1
Этот ответ объясняет, почему это происходит. Чтобы решить эту проблему, я вызываю add-migration
и называю его MERGE
, а затем удаляю любой дублирующий код миграции, который уже произошел. Это просто для обновления снимка модели, чтобы отразить объединенную модель.
Пример:
public partial class MERGE : DbMigration
{
public override void Up()
{
// Intentionally left blank.
// This may seem like a hack, but it is necessary when using source control.
// When a migration is created via add-migration, EF creates
// an .edmx file from the current code first classes. It compares this .edmx to the .edmx stored in the last migration before this,
// which I'll call it parent migration. The edmx snapshots are gzipped and stored in base64 in the resource files (.resx) if you
// want to see them. EF uses the difference between these two snapshots to determine what needs to be migrated.
// When using source control it will happen that two users add entities to the model independently. The generated edmx snapshots will
// only have the changes that they have made. When they merge in source control, they will end up with this:
// Migration | Snapshot Contents
// -------------------------------- | ----------------
// 20150101_Parent Migration | A
// 20150102_Developer 1 Migration | A + Change 1
// 20150103_Developer 2 Migration | A + Change 2
// So calling add-migration will create the current snapshot edmx from the Code First model and compare it to the
// the latest migration snapshot, which is A + Change 2, and see that Change 1 is missing. That is why it
// creates a duplicate migration. We know that the migrations have already been applied, so the only thing that this
// migration will do is update the current snapshot .edmx so that later migrations work fine.
}
public override void Down()
{
}
}
Ответ 2
Я тоже это вижу.
Я не знаю, почему, хотел бы я, но мое решение - сделать добавление-миграцию, которая сделает дубликат.
Теперь этот дубликат открывается в редакторе, а затем я его редактирую, чтобы методы Up и Down были пустыми.
Поэтому результатом является файл миграции, который ничего не делает!
VS счастлив, и вы можете сделать базу данных обновлений без ошибок (до следующего раза).
Надеюсь, это поможет:)
Ответ 3
Я только что столкнулся с той же проблемой.
После создания миграции. Я попытался обновить базу данных и получил следующее сообщение:
Невозможно обновить базу данных в соответствии с текущей моделью, поскольку есть ожидающие изменения и автоматическая миграция отключены. Либо напишите ожидающие изменения модели для миграции на основе кода или автоматического включения миграция. Установить DbMigrationsConfiguration.AutomaticMigrationsEnabled to true, чтобы включить автоматическую миграцию. Вы можете использовать Add-Migration чтобы записать изменения ожидающей модели в перенос на основе кода.
Затем я снова сгенерировал перенос, но он был дублирован.
Проблема решена, когда я Построить проект после создания миграции. Затем Update-Database script найдет способ миграции, и он работает. По крайней мере, для моего случая.
Ответ 4
Это не решение, которое поможет всегда. Я бы порекомендовал также все ответы.
У меня была та же проблема, и предложение от Майка не применимо в моем случае. Я узнал почему...
DLL с миграциями была частью развертывания (sharepoint), а также в GAC (C:\Windows\Microsoft.NET\assembly\GAC_MSIL).
Я удалил DLL из GAC и перезапустил Visual Studio.
Теперь update-database взяла правильную DLL и миграция работала нормально.
Ответ 5
Как общий ответ на эту часть вопроса:
(Я работаю один, но я симулирую командную работу на ветках, чтобы учиться больше о git), и пытаясь привести базу данных в ногу с слияния. Возможно, это произошло из-за миграции в некоторые конкретный заказ после слияния
Да, это вполне может иметь место, EF довольно легко запутаться после слияния, но его можно решить. Ключ к пониманию того, почему он запутался в первую очередь:
Что происходит, когда миграции объединяются из веток?
Причина, по которой EF вводит в заблуждение, заключается в том, что EF сохраняет текущую форму базы данных в фактическом файле миграции, это значение "Target" в файле resx, найденном при каждой миграции, например,
![migration file in solution explorer showing child .resx file]()
![migration resx file showing the Target]()
Представьте, что у вас есть две ветки:
- Ветвь 1: Вы добавляете поле "URL" в таблицу блогов. Поле Target теперь содержит описание базы данных с этим дополнительным полем
- Ветвь 2: Вы добавляете новую таблицу "Ссылки". Опять же, описание базы данных в поле Target теперь содержит эту дополнительную таблицу, но у нее нет поля URL, как это было добавлено в другой ветки
Если вы теперь объедините обе эти ветки обратно в основную ветвь, а затем попытаетесь запустить миграцию, вы вполне можете получить страшные
Невозможно обновить базу данных, чтобы соответствовать текущей модели, потому что есть ожидающие изменения и автоматическая миграция отключена...
Это сообщение об ошибке действительно вводит в заблуждение, но причина ошибки на самом деле довольно проста для понимания:
Почему несколько веток путают EF?
Когда две ветки были объединены обратно с Master, какая из них является последней миграцией (согласно датам в начале имени файла), EF считает истинное текущее состояние базы данных в этом поле цели миграции.
Однако, как мы видели выше, как Ветвь 1, так и Ветвь 2 имеют разные представления о том, каково истинное состояние базы данных (один думает, что есть новое поле URL, другой думает, что есть новое поле ссылок), и бесполезно, что они теперь оба неверны, потому что в базе данных теперь есть оба этих поля.
Сообщение об ошибке возникает потому, что EF вычисляет ожидаемое состояние БД по фактическим шагам миграции и сравнивает его с целью и обнаруживает, что они отличаются.
Как это исправить
Решение всего этого - заставить EF пересчитать состояние базы данных на основе всех миграций, находящихся в настоящее время в проекте, а затем обновить значение Target до значения, включающего изменения, внесенные в все миграции.
Самый простой способ сделать это - просто добавить "пустую" миграцию, используя команду:
Add-Migration <pick_a_name> –IgnoreChanges
Альтернативный подход заключается в перезаписи значения Target в окончательной миграции.
Обратитесь к руководству..
Все вышеперечисленное - это краткий обзор превосходного руководства по пониманию миграций в целом, а также в командной среде, которое можно найти в:
Миграция кода Microsoft в командной среде
На этот документ следует ссылаться в каждом сообщении об ошибке EF, так как в нем есть много повседневных проблем с EF.