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

关于AsNoTrackingWithIdentityResolution()实例解析失效及后台追踪的技术问询

关于EF Core AsNoTrackingWithIdentityResolution()的疑问解答

问题复现代码

// 初始时表为空
Employee emp1 = new Employee()
{
    FirstName = "name1",
    LastName = "name2",
    Salary = 11111
};

context.Add(emp1);
context.SaveChanges();

Employee emp2 = (from e in context.Employees
                 where e.FirstName == "name1"
                 select e).SingleOrDefault();

// 身份解析生效
Console.WriteLine(emp1 == emp2); // 输出 True

Employee emp3 = (from e in context.Employees
                 where e.FirstName == "name1"
                 select e).AsNoTrackingWithIdentityResolution().SingleOrDefault();

// 预期因使用AsNoTrackingWithIdentityResolution()返回True
Console.WriteLine(emp1 == emp3); // 实际输出 False

Employee emp4 = (from e in context.Employees
                 where e.FirstName == "name1"
                 select e).AsNoTrackingWithIdentityResolution().SingleOrDefault();

// 同样未触发身份解析
Console.WriteLine(emp4 == emp3); // 输出 False

使用版本:EF Core 8.0.2
仅当两个实例被上下文变更追踪器追踪时,引用比较才返回True,其他场景下实例未被解析为同一个。


疑问解答

1. 为何使用AsNoTrackingWithIdentityResolution()查询时,同一数据行的实例未被解析为同一个?

这是对该方法功能范围的误解:

  • 该方法的身份解析仅作用于单次查询的执行过程中:它会为当前查询创建一个临时的独立追踪器,确保同一次查询内(比如查询包含关联数据、同一实体多次返回时),同一数据行只会生成一个实体实例。
  • 你代码中的emp3和emp4是两次完全独立的查询,每次查询都会生成自己的临时追踪器,查询结束后该追踪器就会被销毁,因此两次查询生成的实例完全独立,引用比较自然为False。
  • 另外,emp1是被上下文的常规变更追踪器管理的实例,而AsNoTrackingWithIdentityResolution()的临时追踪器与上下文追踪器完全隔离,两者不会共享实例,所以emp1 == emp3必然为False。

2. 该方法的目标是停止追踪,为何后台仍运行独立追踪器?

这里的“停止追踪”指的是不会让上下文的长期变更追踪器持有实体实例,不会跟踪实体后续变更,也不会在上下文生命周期内保留实例引用。而临时独立追踪器是实现身份解析的必要手段:

  • 身份解析需要一个容器来记录已创建的实体实例,避免同一数据行生成重复实例,这个临时追踪器就是干这个的。
  • 这个临时追踪器是查询专属的,查询执行完毕后会立即被回收,不会像上下文追踪器那样长期存在,因此不会造成持续的内存占用或变更跟踪开销,完全符合“不追踪”的核心目标。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 02:20:37