【问题标题】:Change data in migration Up method - Entity Framework在迁移 Up 方法中更改数据 - 实体框架
【发布时间】:2016-02-04 15:26:43
【问题描述】:

我在现有模型中添加了一个新属性。这是一个布尔属性,默认值为 true。此表中有现有数据,我想在 Up 方法中创建新字段后立即将特定行的新属性设置为 false。

public override void Up()
    {
        AddColumn("dbo.RequestValidationErrors", "IsBreaking", c => c.Boolean(nullable: false));
        using (Context ctx = new Context())
        {
            var validation = ctx.RequestValidationErrorSet.FirstOrDefault(x => x.WordCode == "RequestValidationError.MoreThanOneItemFound");
            if (validation != null)
            {
                validation.IsBreaking = false;
                ctx.SaveChanges();
            }
        }
    }

这样EF在说的时候会报错

System.InvalidOperationException:模型支持 自数据库创建以来,“DbContext”上下文已更改。 考虑使用 Code First 迁移来更新数据库

是否可以在这里更改数据库,还是应该在其他地方更改?

【问题讨论】:

    标签: c# asp.net-mvc entity-framework entity-framework-migrations


    【解决方案1】:

    除了使用Sql 方法,您还可以使用UpdateData 方法。

    migrationBuilder.UpdateData(
        table: "RequestValidationErrors", 
        keyColumn: "WordCode", 
        keyValue: "RequestValidationError.MoreThanOneItemFound", 
        column: "IsBreaking", 
        value: false);
    

    (不知道是不是只有ef core支持这种方式)

    【讨论】:

    • EF Core 从 v2.1 开始支持此功能
    • 这在 ASP.NET Core 3.1 中按预期工作。一个小的改进是尽可能使用 nameof(例如 nameof(RequestValidationErrors)、nameof(RequestValidationErrors.WordCode)、nameof(RequestValidationErrors,IsBreaking)。
    • 我是 EF Core 的新手,但我认为使用 nameof 不是一个好主意。每次迁移只是关于如何根据数据库的当前状态更新(或降级)模式的描述。这可以递归地应用,以便升级多个模式版本。在迁移中使用 nameof 会将您的迁移逻辑与代码状态耦合,因此可能会失败,因为属性名称的更改现在会影响过去使用 nameof(property) 的所有迁移逻辑。
    【解决方案2】:

    在迁移过程中,最好使用Sql()方法更新数据库数据。

    Sql("UPDATE dbo.RequestValidationErrors SET IsBreaking = 0 WHERE WordCode = 'RequestValidationError.MoreThanOneItemFound'");
    

    您还应该为新列定义默认值。所以解决方案应该是这样的:

    public override void Up()
    {
        AddColumn("dbo.RequestValidationErrors", "IsBreaking", c => c.Boolean(nullable: false, default: true));
        Sql("UPDATE dbo.RequestValidationErrors SET IsBreaking = 0 WHERE WordCode = \"RequestValidationError.MoreThanOneItemFound\"");
    }
    

    在迁移过程中使用DbContext 是非常不明确的。你对上下文有什么期望?它的模型中有迁移后状态,但数据库的表中有迁移前状态。所以模型和数据库不匹配。如果您仍然坚持在代码中使用DbContext,则禁用模型检查可能是解决方案。您可以使用以下方法禁用模型检查:

    Database.SetInitializer<Log4ProContext>(null);
    

    【讨论】:

    • 感谢您的解决方案以及缺少的 defaultValue。
    • 当你找到你要找的东西时感觉非常好,你的朋友回答了:)
    • 你是什么意思“最好使用Sql()”?比使用上下文更好?比使用 UpdateData 方法更好?
    【解决方案3】:

    为 EF6 编写 DataMigration 可能是一件苦差事。我们整理了一个库,我只是在这里开源供其他人使用,它为 EF6 添加了这个承诺已久但缺少的功能。只需使用常规 EF 查询等编写类。

    https://github.com/b9chris/Brass9.Data

    【讨论】:

      【解决方案4】:

      如果您想使用框架进行此类更改,您应该将数据库更改与数据更改分开。

      仅为数据库更改创建迁移,然后执行。

      然后创建一个新的迁移(Up() 和 Down() 方法将为空)。您现在可以实例化您的 DatabaseContext 并且不会出现错误。这样您就可以使用框架进行这些更改,并正确实现 Down() 方法。

      【讨论】:

      • 这个“解决方案”非常危险,因为它一开始看起来很有效,但事实并非如此。一旦您创建另一个更改数据库模型的迁移,它就不再起作用,因为您无法创建数据库上下文,因为模型不再是数据库
      • @NoConnection 由于这个原因,您永远不应该在迁移中使用您的 DbContext 实例。使用migrationBuilder.Sql.UpdateData 方法迁移您的数据应该不会有问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-03
      • 2019-06-24
      • 2014-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多