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

C# 向列表添加对象前更新时同id对象同步修改该如何解决

问题原因

EF Core的DbContext默认开启实体跟踪机制:在同一个_context实例的生命周期内,只要是通过该上下文查询得到的实体,相同主键ID的实体始终会指向同一个内存引用对象。你多次查询同ID的Item,实际拿到的都是同一个对象的引用,所以修改属性后,列表中之前插入的同ID对象自然会同步更新。
另外你代码中Item newItem = new Item();是无效代码,下一行查询结果直接覆盖了该变量,刚创建的新对象会被GC回收。

解决方案
  • 方案1:查询时关闭跟踪(推荐无后续入库需求的场景)
    查询时添加AsNoTracking()方法,上下文不会缓存跟踪返回的实体,每次查询都会生成新的对象实例。
    修改后的代码如下:
List<Item> lst = new List<Item>();         
foreach (Item currItemB in itemsB)
{
    Item newItem = await _context.Item.AsNoTracking()
        .Where(x => x.id == currItemB.id)
        .FirstOrDefaultAsync();
    newItem.param = currItemB.param;
    lst.Add(newItem);
}

注意:该方案返回的实体不在上下文跟踪范围内,如果后续需要将实体更新回数据库,需要手动调用_context.Update(newItem)附加后再保存。

  • 方案2:手动映射新实体(最稳妥可控)
    不要直接将查询到的跟踪实体赋值给最终添加到列表的变量,自己手动新建Item实例,拷贝查询结果的属性值,从根源上保证实例独立。
    代码示例:
List<Item> lst = new List<Item>();         
foreach (Item currItemB in itemsB)
{
    Item dbItem = await _context.Item
        .Where(x => x.id == currItemB.id)
        .FirstOrDefaultAsync();
    // 手动拷贝所有需要的属性
    Item newItem = new Item()
    {
        id = dbItem.id,
        // 其他属性依次赋值
        param = currItemB.param
    };
    lst.Add(newItem);
}
  • 方案3:深拷贝实体
    如果实体属性较多不想手动赋值,可以通过深拷贝的方式复制查询到的实体得到新实例,常见实现方式包括手动编写拷贝构造函数、序列化反序列化、使用AutoMapper等映射库配置深度映射。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 16:42:00