EF Core配置单个导航属性报错:违反唯一约束IX_ItemDB_CategoryID
我正在开发一个基于EF Core的项目,希望通过单个导航属性使用Category的外键,让Item存储Category的外键并能显示分类名称。
实体类定义
[Table("Item" , Schema = "public")] public class Item { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int ItemID {get; set;} public string Name {get; set;} public int CategoryID {get; set;} //Single Navigation Property public Category Category {get; set;} } [Table("Category" , Schema = "public")] public class Category { [Key] [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int CategoryID {get; set;} public string Name {get; set;} }
DbContext配置代码
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Item>().ToTable("Item"); modelBuilder.Entity<Category>().ToTable("Category"); modelBuilder.Entity<Item>() .HasOne(i=>i.Category) .WithOne() .HasForeignKey<Item>(i=>i.CategoryID); }
运行时错误
Duplicate key value violates unique constraint "IX_ItemDB_CategoryID"
显然这意味着Item中的CategoryID不能重复,请问我哪里配置错误了?
问题原因与解决方法
原因
你用.WithOne()配置关联关系时,EF Core会默认识别为一对一关系:即一个Item对应一个Category,同时一个Category也只能对应一个Item。为了保证这个约束,EF Core会自动给Item表的CategoryID字段添加唯一索引,所以当你尝试给多个Item设置同一个CategoryID时就会触发唯一键冲突错误。
但你的实际需求应该是一对多关系:一个Category可以被多个Item关联,一个Item只属于一个Category。
解决方法
把配置中的.WithOne()改成.WithMany()即可,无需在Category类中定义反向导航属性(满足你单导航属性的需求),EF Core会自动识别这是一对多关系,不会给CategoryID添加唯一约束。
修改后的DbContext配置代码:
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Item>().ToTable("Item"); modelBuilder.Entity<Category>().ToTable("Category"); modelBuilder.Entity<Item>() .HasOne(i => i.Category) .WithMany() // 修改为WithMany,无需指定反向导航 .HasForeignKey(i => i.CategoryID); }
如果后续需要在Category类中添加反向导航属性(比如public ICollection<Item> Items { get; set; }),只需把.WithMany()改成.WithMany(c => c.Items)即可,当前的配置已经能满足你单导航属性的需求。
内容的提问来源于stack exchange,提问作者AsM

