一、环境
windows 10
Visual studio 2022
dotnet 6.0.404
Microsoft.EntityFrameworkCore.Tools 6.0.14
二、问题
有一记录房产交易数据的实体,已有生产数据,现需更改、添加字段,产生了迁移不成功和数据丢失的问题。
原实体定义
//唯一复合索引
[Index(nameof(Name), nameof(TradeDay), IsUnique = true)]
public class HouseTrade
{
[Key]
[Required]
public int HouseTradeID { get; set; }
[Required]
[MaxLength(100)]
public string Name { get; set; }
public int TotalTrades { get; set; }
//总面积
public float TotalArea { get; set; }
public int HouseTrades { get; set; }
//其中住宅面积
public float HouseArea { get; set; }
[Required]
[MaxLength(20)]
public string TradeDay { get; } = DateTime.Now.ToShortDateString();
public HouseTrade()
{
}
public string toString()
{
return Name + "\t" + TotalTrades+ "\t" + TotalArea + "\t" + HouseTrades + "\t" + HouseArea+"\t"+TradeDay;
}
}
现不再需要记录交易面积,仅简单描述 住宅面积-总面积 以字符串存储就可以。 现在模型中可以删去TotalArea、HouseArea,然后增加字段 Description = HouseArea + '-' + TotalArea。现模型如下所示:
//唯一复合索引
[Index(nameof(Name), nameof(TradeDay), IsUnique = true)]
public class HouseTrade
{
[Key]
[Required]
public int HouseTradeID { get; set; }
[Required]
[MaxLength(100)]
public string Name { get; set; }
public int TotalTrades { get; set; }
//public float TotalArea { get; set; }
public int HouseTrades { get; set; }
//public float HouseArea { get; set; }
[MaxLength(200),AllowNull]
public string Description { get; set; }
[Required]
[MaxLength(20)]
public string TradeDay { get; } = DateTime.Now.ToShortDateString();
public HouseTrade()
{
}
public string toString()
{
return Name + "\t" + TotalArea + "\t" + HouseTrades + "\t" +Description+"\t"+TradeDay;
}
}
此时若直接用update-database,则原有数据将丢失,所以在生成迁移后,用手动进行更改以保护数据。
三、解决办法
在控制台执行Add-Migration 。
PM> Add-Migration addDescription
Build started...
Build succeeded.
An operation was scaffolded that may result in the loss of data. Please review the migration for accuracy.
To undo this action, use Remove-Migration.
默认在Migrations文件下会生成二个文件。
打开20230915024552_addDescription.cs文件,可以看到迁移将要进行的操作,若此时立即操作,原有TotalArea、TradeArea数据将丢失。
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "HouseArea",
table: "HouseTrades");
migrationBuilder.DropColumn(
name: "TotalTrades",
table: "HouseTrades");
migrationBuilder.AddColumn(
name: "Description",
table: "HouseTrades",
type: "nvarchar(200)",
maxLength: 200,
nullable: false,
defaultValue: "");
}
此时手动修改代码,先创建Description字段,然后再将数据插入,然后再删除旧字段。
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn(
name: "Description",
table: "HouseTrades",
type: "nvarchar(200)",
maxLength: 200,
nullable: false,
defaultValue: "");
migrationBuilder.Sql(
@"
UPDATE HouseTrades
SET Description = CONVERT(VARCHAR(30),HouseTrades) + '-' + CONVERT(VARCHAR(30),TotalTrades);
");
migrationBuilder.DropColumn(
name: "HouseArea",
table: "HouseTrades");
migrationBuilder.DropColumn(
name: "TotalTrades",
table: "HouseTrades");
}
保存后再执行,update-database
PM> update-database
Build started...
Build succeeded.
Applying migration '20230915024552_addDescription'.
Done.
数据迁移成功。
四、参考文章
管理迁移 - EF Core | Microsoft Learn