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

EF Core InMemoryDatabase添加关联产品订单时实体跟踪异常求助

问题分析

你遇到的InvalidOperationException是因为EF Core的实体跟踪机制冲突:当调用_dbContext.Pedido.Add(pedido)时,EF会自动递归标记所有关联的Produtos实例为Added状态,但Id=1的Produtos已经存在于InMemory数据库中,且当前DbContext已经在跟踪该实体的另一个实例,导致同一Key的两个实例被同时跟踪,触发异常。

这种情况通常发生在:

  • 请求传入的Produtos是从JSON绑定生成的新实例,但该Id对应的产品已存在于数据库
  • DbContext生命周期过长,之前的查询操作已经跟踪了该产品实例
解决方案

方案1:关联已存在的产品实例(推荐)

订单关联的产品应为数据库中已存在的实体,因此需要将请求中的产品替换为DbContext中已跟踪的实例,确保EF只处理同一个实例:

public Pedidos Adicionar(Pedidos pedido)
{
    // 替换订单中的产品为数据库中已存在的实例
    for (int i = 0; i < pedido.ProdutosPedido.Count; i++)
    {
        var produto = pedido.ProdutosPedido[i];
        var existingProduto = _dbContext.Produto.Find(produto.Id);
        
        if (existingProduto != null)
        {
            pedido.ProdutosPedido[i] = existingProduto;
        }
        // 若产品不存在,可根据业务需求选择添加新产品或抛出异常
        // else _dbContext.Produto.Add(produto);
    }

    _dbContext.Pedido.Add(pedido);
    _dbContext.SaveChanges();
    return pedido;
}

方案2:手动设置产品实体状态

如果确认产品已存在,可手动将关联的产品标记为Unchanged,告诉EF不需要修改或添加这些产品:

public Pedidos Adicionar(Pedidos pedido)
{
    _dbContext.Pedido.Add(pedido);
    
    // 标记所有关联产品为已存在状态
    foreach (var produto in pedido.ProdutosPedido)
    {
        _dbContext.Entry(produto).State = EntityState.Unchanged;
    }

    _dbContext.SaveChanges();
    return pedido;
}

方案3:修正实体关系配置

确保EF正确识别Pedidos与Produtos的多对多关系,避免自动添加重复实体:

在EFDBContext中添加关系配置:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    // 配置订单与产品的多对多关系
    modelBuilder.Entity<Pedidos>()
        .HasMany(p => p.ProdutosPedido)
        .WithMany(); // 若Produtos中有反向导航属性,可改为.WithMany(prod => prod.Pedidos)
}

方案4:检查DbContext生命周期

确保DbContext使用短生命周期(比如ASP.NET Core中的Scoped模式),避免长时间持有导致旧的跟踪实例未释放。

内容的提问来源于stack exchange,提问作者AgnesJes

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 13:01:16