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

Ошибка обновления базы данных из-за ожидающих изменений, но 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 тоже), и пытается получить базу данных в шаге с слиянием. Возможно, это произошло из-за переноса миграции в определенном порядке после слияния - хотя отмечено, миграция действительно работала, как ожидалось, в том порядке, в котором они выполнялись, когда я дал им пустую БД.

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

4b9b3361

Ответ 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.