我读了一篇关于 AsNoTrackingWithIdentityResolution() 方法的文章,它是一种无需跟踪即可进行身份解析的方法,并且在使用它时,与上下文不同的更改跟踪器在后台运行,以解析所引用的实体到一个实例的同一行。
我尝试通过运行以下代码来验证这一点,但实例未解析为一个实例
// Initially the table is empty
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();
// Identity resolution takes place
Console.WriteLine(emp1 == emp2); // True
Employee emp3 = (from e in context.Employees
where e.FirstName == "name1"
select e).AsNoTrackingWithIdentityResolution().SingleOrDefault();
// Expected to give True due to using AsNoTrackingWtihIdentityResolution()
Console.WriteLine(emp1 == emp3); // but found False
Employee emp4 = (from e in context.Employees
where e.FirstName == "name1"
select e).AsNoTrackingWithIdentityResolution().SingleOrDefault();
// Also no identity resolution happened
Console.WriteLine(emp4 == emp3); // False
仅当上下文更改跟踪器跟踪两个比较实例(解析为一个实例),而其他实例未解析为一个实例时,引用比较才会给出 true。我正在使用 EF core 8.0.2
所以现在:
AsNoTrackingWithIdentityResolution
不要使用缓存(跟踪)实体,您的测试是错误的。
此模式仅在查询范围内有效。它重用由
Include
指令加载的实体来修复导航属性,并且不会实例化相同类型和相同键的重复实体。这就是为什么它被称为WithIdentityResolution
。
例如,如果您有以下课程:
class Employee
{
public int Id { get; set; }
public ICollection<Order> Orders { get; set; }
}
class Orders
{
public int Id { get; set; }
public int EmployeeId { get; set; }
public Employee Employee { get; set; }
}
并查询:
var result = context.Employees
.Include(e => e.Orders)
.ThenInclude(o => o.Employee) // can be omitted, just shows what we are trying to load
.AsNoTrackingWithIdentityResolution();
这意味着每个加载的员工都会有带有初始化
Employee
导航属性的订单,并且使用身份解析具有相同的引用。
没有
.ThenInclude(o => o.Employee)
的相同查询也应该初始化 Orders 的 Employee
属性,因为 Employeee 已加载到查询中,并且身份解析可以在查询的初始化范围中找到它们。
仅使用
AsNoTracking()
将为每个订单实例化新的 Employee 对象。
IOW,如果您正在加载大对象图,此方法很有用,它可能会减少内存使用量和查询复杂性。