You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 15:36:01