EF Core两张表关联同一Category表触发Id唯一约束报错如何解决
问题根本原因
你传入CreateDeadline方法的Category实例是从其他DbContext查询得到的游离态实体,当你在底层Create方法中新建了独立的DbContext、直接调用AddAsync添加Deadline实体时,EF Core会默认把所有关联的游离态实体标记为Added新增状态,尝试往Category表插入重复Id的记录,因此触发了唯一约束报错。
解决方案
方案1:显式关联外键Id(最推荐)
给Deadline和Transaction实体显式添加Category外键属性,创建关联时只赋值外键Id即可,不需要传递整个Category实体:
public class Deadline : DomainObject { public Account Tiers { get; set; } // 类型和DomainObject的Id类型保持一致即可 public Guid CategoryId { get; set; } public Category Category { get; set; } public DateTime Created_On { get; set; } } public class Transaction : DomainObject { public Account Payee { get; set; } public Guid CategoryId { get; set; } public Category Category { get; set; } public DateTime DateProcessed { get; set; } }
创建Deadline时修改赋值逻辑:
Deadline deadline = new Deadline() { // 其余属性保持不变 CategoryId = category.Id, Category = null, // 不需要赋值已存在的Category实例 // 其余属性保持不变 };
该方案不需要额外数据库查询,性能最优,逻辑也最清晰。
方案2:将游离态Category附加到当前上下文
修改底层Create方法,手动标记关联的Category为已存在状态,避免EF Core重复插入:
public async Task<Deadline> Create(Deadline entity) { using (BookkeepingDbContext context = _contextFactory.CreateDbContext()) { // 关联的Category是游离态,附加到上下文标记为未修改 if (entity.Category != null) { context.Attach(entity.Category).State = EntityState.Unchanged; } // 如果Account也是从其他上下文传入的游离态实体,同样需要附加 if (entity.Account != null) { context.Attach(entity.Account).State = EntityState.Unchanged; } EntityEntry<Deadline> createdResult = await context.Set<Deadline>().AddAsync(entity); await context.SaveChangesAsync(); return createdResult.Entity; } }
方案3:当前上下文重新查询Category
在插入Deadline前,用当前的DbContext重新查询已存在的Category实例,再赋值关联:
public async Task<Deadline> Create(Deadline entity) { using (BookkeepingDbContext context = _contextFactory.CreateDbContext()) { if (entity.Category != null) { var existedCategory = await context.Set<Category>().FindAsync(entity.Category.Id); entity.Category = existedCategory; } EntityEntry<Deadline> createdResult = await context.Set<Deadline>().AddAsync(entity); await context.SaveChangesAsync(); return createdResult.Entity; } }
额外优化建议
你当前的Fluent API配置缺少Category和另外两个实体的关联规则,建议补全避免EF Core生成不符合预期的约束:
modelBuilder.Entity<Deadline>() .HasOne(e => e.Category) .WithMany() // 如果Category没有对应的Deadline集合属性可以留空 .OnDelete(DeleteBehavior.Restrict); // 按业务需求调整删除行为 modelBuilder.Entity<Transaction>() .HasOne(e => e.Category) .WithMany() .OnDelete(DeleteBehavior.Restrict);
内容的提问来源于stack exchange,提问作者Steekse
相关产品推荐
相关产品推荐

