配置EF Core一对一关联报错:主键Id无法作为外键
解决EF Core一对一关联配置问题
问题描述
有两个继承自EntityBase的实体,Document需关联Price,二者的Id均为自动生成的主键。尝试通过以下代码配置一对一关联,期望Document表中存在指向Price的外键:
public void Configure(EntityTypeBuilder<Document> builder) { builder.HasOne<Price>(x => x.Price) .WithOne() .HasForeignKey<Price>(x => x.Id) .OnDelete(DeleteBehavior.Restrict); }
实体定义:
public abstract class EntityBase { [Key, DatabaseGenerated(DatabaseGeneratedOption.Identity), Column(Order = 0)] public Guid Id { get; set; } } public class Price : EntityBase { [MinLength(1), MaxLength(255)] public string Type { get; set; } = null!; } public class Document : EntityBase { public string Name { get; set; } = null!; public virtual Price? Price { get; set; } }
执行Add-Migration时报错:
属性'Id'无法作为Price的外键,因为它是由存储生成的值,且属于基类EntityBase定义的键{'Id'}。请将'Id'配置为'ValueGeneratedNever',或改为在Price上定义外键。
不想在Price中重新定义Id,寻求其他解决方法。
解决方案
问题出在你把Price的主键Id设为了外键,而它本身是自动生成的标识列,EF Core不允许这样的配置。要实现Document表包含指向Price的外键,需要把外键放在Document实体中,具体步骤如下:
- 修改Document实体,添加外键属性
在Document类中新增PriceId属性,作为关联Price的外键:
public class Document : EntityBase { public string Name { get; set; } = null!; public Guid? PriceId { get; set; } // 新增外键属性,可空对应Price导航属性的可空 public virtual Price? Price { get; set; } }
- 修改Fluent API配置
调整关联配置,指定外键在Document上:
public void Configure(EntityTypeBuilder<Document> builder) { builder.HasOne(d => d.Price) .WithOne() // 若不需要Price到Document的反向导航,保持空即可 .HasForeignKey<Document>(d => d.PriceId) // 外键绑定到Document的PriceId属性 .OnDelete(DeleteBehavior.Restrict); }
如果需要双向导航,可在Price中添加Document导航属性:
public class Price : EntityBase { [MinLength(1), MaxLength(255)] public string Type { get; set; } = null!; public virtual Document? Document { get; set; } }
此时配置改为:
builder.HasOne(d => d.Price) .WithOne(p => p.Document) .HasForeignKey<Document>(d => d.PriceId) .OnDelete(DeleteBehavior.Restrict);
这样配置后,Document表会生成PriceId列作为外键指向Price的Id,同时保留两个实体的Id作为自动生成的主键,无需修改基类或重新定义Id。
内容的提问来源于stack exchange,提问作者Greg
相关产品推荐
相关产品推荐

