在迁移中更改数据Up方法-实体框架
本文关键字:方法 实体 框架 Up 数据 迁移 | 更新日期: 2023-09-27 18:20:37
我在现有模型中添加了一个新属性。它是一个bool属性,默认值为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"上下文已更改。考虑使用代码优先迁移来更新数据库
可以在这里更改数据库吗?还是应该在其他地方更改?
在迁移过程中,最好使用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'"");
}
在迁移过程中使用 更新: 从EF Core 2.1开始,对于更简单的情况,您可以使用 我的建议是在迁移中根本不要将DbContext
是非常模糊的。你期望从上下文中得到什么?它的模型中有迁移后状态,但数据库的表中有迁移前状态Database.SetInitializer<Log4ProContext>(null);
UpdateData
而不是Sql
方法,就像@ntfrex在回答中提到的那样:migrationBuilder.UpdateData(
table: "RequestValidationErrors",
keyColumn: "WordCode",
keyValue: "RequestValidationError.MoreThanOneItemFound",
column: "IsBreaking",
value: false);
nameof
运算符用于表和列名。因为以后重命名这些类会导致旧的迁移在生产中失败,因为数据库中的表名仍然使用旧名称。
不使用Sql
方法,也可以使用UpdateData
方法。
migrationBuilder.UpdateData(
table: "RequestValidationErrors",
keyColumn: "WordCode",
keyValue: "RequestValidationError.MoreThanOneItemFound",
column: "IsBreaking",
value: false);
(我不知道是否只有ef核心支持这种方法)
如果您想使用框架进行这样的更改,您应该将数据库更改与数据更改分开。
只为数据库更改创建一个迁移,然后执行。
然后创建一个新的迁移(Up()和Down()方法将为空)。您现在可以实例化您的DatabaseContext,并且不会出现任何错误。通过这种方式,您可以使用Framework进行这些更改,并正确地实现Down()方法。
为EF6编写DataMigrations可能是一件苦差事。我们建立了一个库,我只是在这里开源供其他人使用,这为EF6添加了这个承诺已久、缺失的功能。只需使用常规EF查询等编写类。
https://github.com/b9chris/Brass9.Data