由于Pending Changes,Update-Database失败,但Add-Migration创建了重复迁移

时间:2013-07-29 10:38:48

标签: c# entity-framework ef-migrations

我正在使用Entity Framework 5.0 Code 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的信息,并尝试将数据库与合并一起使用。这可能是因为合并后以某种特定顺序放置迁移 - 虽然有一点需要注意,迁移 按照我们给他们一个空数据库时的运行顺序按预期工作。

此外,当表中包含数据时,需要手动调整此原始迁移,因为需要将数据从旧列复制到新列。但是,我在该文件中使用和不使用手动编辑测试了该文件,但仍然遇到了所记录的行为。

5 个答案:

答案 0 :(得分:29)

This answer explains why it happens。要解决此问题,请致电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's 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's Migration |  A + Change 1
        // 20150103_Developer 2's 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's 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()
    {

    }
}

答案 1 :(得分:4)

我也一直看到这个。 我不知道为什么,希望我这样做,但我的解决方案是进行添加迁移,这将导致重复。 现在这个副本在编辑器中打开,然后我编辑它,以便Up和Down方法为空。 所以结果是一个什么都不做的迁移文件! VS很高兴你可以毫无错误地进行更新数据库(直到下次)。

我希望这会有所帮助:)

答案 2 :(得分:0)

我刚遇到同样的问题。

创建迁移后。我尝试更新数据库并收到以下消息:

  

无法更新数据库以匹配当前模型,因为有   挂起的更改和自动迁移已禁用。要么写   待定模型更改为基于代码的迁移或启用自动   移民。将DbMigrationsConfiguration.AutomaticMigrationsEnabled设置为   如果启用自动迁移,则为true您可以使用添加迁移   命令将挂起的模型更改写入基于代码的迁移。

然后,我再次生成了迁移,但它是重复的。

创建迁移后,构建项目时问题解决了。然后Update-Database脚本找到迁移方法,它可以工作。至少对我而言。

答案 3 :(得分:0)

这不是解决方案,总是有帮助的。我也会推荐所有答案。

我遇到了同样的问题,麦克的建议不适用于我的情况。我知道了为什么...

具有迁移 DLL 是(共享点)部署的一部分,并且是 GAC (C:\ Windows \ Microsoft。 NET \ assembly \ GAC_MSIL)。

我从GAC中删除了DLL,然后重新启动了Visual Studio。

现在,“更新数据库”使用了正确的DLL,并且迁移工作正常。

答案 4 :(得分:0)

作为对这一部分问题的一般回答:

  

(我一个人工作,但正在模拟团队在分支机构的工作以学习   以及有关git的更多信息),并尝试与   合并。可能是由于将迁移放入某些   合并后的特定顺序

是的,这很可能是事实,合并后EF很容易混淆,但是有可能解决它。关键是首先要弄清为什么会混淆:

从分支合并迁移会发生什么?

EF之所以感到困惑,是因为EF将数据库的当前形状存储在实际的迁移文件中,它是每次迁移下在resx文件中找到的“目标”值,例如

migration file in solution explorer showing child .resx file

migration resx file showing the Target

假设您有两个分支:

  • 分支1:您将“ URL”字段添加到Blog表中。现在,“目标”字段具有该数据库的说明,并带有该额外字段
  • 分支2:您添加了一个新的“链接”表。再一次,“目标”字段中的数据库描述现在具有该额外的表,但是它没有URL字段,因为它是在另一个分支上添加的

如果您现在将这两个分支都合并回master分支,然后尝试运行迁移,您很可能会感到恐惧

  

由于存在以下原因,无法更新数据库以匹配当前模型   待更改,自动迁移已禁用...

该错误消息确实无助于误导,但错误原因实际上很容易理解:

为什么多个分支机构会混淆EF?

当两个分支合并回Master时,它们中的任何一个现在是最后一次迁移(根据文件名开头的日期),EF认为该分支在该迁移的Target中具有数据库的真实当前状态字段。

但是,正如我们在上面看到的,分支1和分支2都对数据库的真实状态有不同的看法(一个认为存在一个新的URL字段,另一个认为存在一个新的链接字段),并且无助于他们现在两者都是错误的,因为数据库现在同时具有这两个字段。

发生错误消息是因为EF根据迁移的实际步骤计算了数据库的预期状态,并将其与目标进行比较,发现它们是不同的。

如何修复

所有这些解决方案是强制EF基于项目中现在的所有迁移重新计算数据库的状态,然后将Target值更新为包含对 all 所做的更改的值>迁移。

最简单的方法是使用以下命令添加“空白”迁移:

Add-Migration <pick_a_name> –IgnoreChanges

另一种方法是在最终迁移过程中覆盖目标值。

咨询该手册。

以上所有内容都是对全面了解迁移以及在团队环境中了解迁移的精湛指南的简要概述,

Microsoft's Code First Migrations in Team Environments

每份EF错误消息中均应引用该文档,因为它可以解决许多日常EF问题。