我在现有模型中添加了一个新属性。它是一个布尔属性,默认值为 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 迁移来更新数据库
是否可以在这里更改数据库或者我应该在其他地方进行更改?
在迁移过程中,最好使用 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);
更新:
从 EF Core 2.1 开始,您可以使用 UpdateData
而不是 Sql
方法来处理更简单的情况,就像@ntfrex 在答案中提到的那样:
migrationBuilder.UpdateData(
table: "RequestValidationErrors",
keyColumn: "WordCode",
keyValue: "RequestValidationError.MoreThanOneItemFound",
column: "IsBreaking",
value: false);
我的建议是 NOT TO USE nameof
运算符用于迁移中的表名和列名。因为稍后重命名这些类会导致旧迁移在生产中失败,因为数据库中的表名仍然使用旧名称。
除了使用 Sql
方法,您还可以使用 UpdateData
方法。
migrationBuilder.UpdateData(
table: "RequestValidationErrors",
keyColumn: "WordCode",
keyValue: "RequestValidationError.MoreThanOneItemFound",
column: "IsBreaking",
value: false);
(不知道是不是只有ef core支持这种方式)
如果您想使用框架进行此类更改,则应将数据库更改与数据更改分开。
仅为数据库更改创建迁移,然后执行。
然后创建一个新的迁移(Up() 和 Down() 方法将为空)。您现在可以实例化您的 DatabaseContext 并且不会出现错误。通过这种方式,您可以使用框架进行这些更改,并正确实现 Down() 方法。
migrationBuilder.Sql
或 .UpdateData
方法迁移您的数据,因为应该没有问题。
为 EF6 编写 DataMigration 可能是一件苦差事。我们整理了一个库,我只是在这里开源供其他人使用,它为 EF6 添加了这个承诺已久但缺少的功能。只需使用常规 EF 查询等编写类。
https://github.com/b9chris/Brass9.Data
UpdateData
不可用。我刚刚更新了答案:)