EF Core迁移报错:未提供ShopId1值的原因及解决方法
我需要构建一个OrderNumber表,用于为每个店铺存储对应的订单编号。将ShopId设置为OrderNumber的主键后,执行dotnet ef migrations add InitializeOrderNumber命令时出现如下错误:
Build started...
Build succeeded.
System.InvalidOperationException: 实体类型'OrderNumber'的种子实体无法添加,因为未提供必填属性'ShopId1'的值。
...
实体类型'OrderNumber'的种子实体无法添加,因为未提供必填属性'ShopId1'的值。
请问EF Core为何会生成ShopId1属性?该如何修复这个错误?
相关代码如下:
Shop实体类
public class Shop { public int Id { get; set; } public string Name { get; set; } = default!; }
OrderNumber实体类
public class OrderNumber { [Key] public int ShopId { get; set; } public Shop Shop { get; set; } = default!; public int Number { get; set; } }
Shop配置类
public class ShopConfiguration : IEntityTypeConfiguration<Shop> { public static readonly Shop[] Shops = { new() { Id = 1, Name = "Shop1" }, new() { Id = 2, Name = "Shop2" } }; public void Configure(EntityTypeBuilder<Shop> builder) { builder.HasData(Shops); } }
OrderNumber配置类
public class OrderNumberConfiguration:IEntityTypeConfiguration<OrderNumber> { public void Configure(EntityTypeBuilder<OrderNumber> builder) { var shops = ShopConfiguration.Shops; builder.HasData( new OrderNumber { ShopId = shops[0].Id, Number = 1 }, new OrderNumber { ShopId = shops[1].Id, Number = 1 } ); } }
为何生成ShopId1属性?
EF Core遵循约定优先原则,但这里它没能正确识别你的关联配置:你把OrderNumber的ShopId设为主键,同时声明了导航属性Shop,但EF Core没有自动将这个ShopId识别为关联Shop的外键。它默认会为Shop导航属性生成名为ShopId的外键字段,发现该字段已被用作主键后,就自动创建了新的外键字段ShopId1来关联Shop实体,最终导致种子数据因缺少这个自动生成的外键值而报错。
修复方案
需要显式配置OrderNumber与Shop的关联关系,明确告诉EF Core:OrderNumber的主键ShopId就是关联Shop的外键。修改OrderNumberConfiguration类的Configure方法:
public class OrderNumberConfiguration:IEntityTypeConfiguration<OrderNumber> { public void Configure(EntityTypeBuilder<OrderNumber> builder) { // 显式配置:ShopId既是主键也是关联Shop的外键,且Shop无反向导航属性 builder.HasOne(ot => ot.Shop) .WithOne() .HasForeignKey<OrderNumber>(ot => ot.ShopId); var shops = ShopConfiguration.Shops; builder.HasData( new OrderNumber { ShopId = shops[0].Id, Number = 1 }, new OrderNumber { ShopId = shops[1].Id, Number = 1 } ); } }
修改完成后,重新执行dotnet ef migrations add InitializeOrderNumber命令即可正常生成迁移文件。
内容的提问来源于stack exchange,提问作者phasetr

