附加到多个DbContext的实体的引用相等性技术问询
这个问题问到点子上了,刚好戳中EF Core上下文缓存的核心逻辑——我来给你拆解清楚:
首先得明确一个核心前提:每个DbContext的ChangeTracker(实体缓存)是完全独立的。单个上下文内的实体引用相等,本质是EF会优先从自己的缓存里返回已存在的实例,而非每次查询都新建对象。那跨上下文附加的情况,得分两边来看:
对于手动附加了实体的dbContext2:
当你把来自dbContext1的实体实例附加到dbContext2后,这个实例就被存入了dbContext2的ChangeTracker缓存。之后你在dbContext2里查询同一数据库对象(比如用dbContext2.Entities.Find(id)或者LINQ查询),EF Core会直接从缓存里返回你之前附加的那个实例,所以此时查询结果和你附加的实体是引用相等的。对于原始的dbContext1:
dbContext1的缓存和dbContext2完全隔离,它只会维护自己范围内的实体实例。之后你在dbContext1里查询同一数据库对象,EF Core还是会从它自己的缓存里返回最初的那个实例——这个实例和dbContext2里的那个是不同的引用,因为两个上下文各自持有独立的实体对象。
举个简单的代码例子帮你理解:
// 从dbContext1获取实体 var entityFromDb1 = dbContext1.Entities.First(e => e.Id == 1); // 附加到dbContext2 dbContext2.Entities.Attach(entityFromDb1); // dbContext2查询同一实体 var entityFromDb2Query = dbContext2.Entities.Find(1); Console.WriteLine(entityFromDb1 == entityFromDb2Query); // 输出 True(引用相等) // dbContext1再次查询同一实体 var entityFromDb1Query = dbContext1.Entities.Find(1); Console.WriteLine(entityFromDb1 == entityFromDb1Query); // 输出 True(单个上下文内的引用相等) Console.WriteLine(entityFromDb1 == entityFromDb2Query); // 输出 False(跨上下文的引用不同)
补充个小细节:不管你在dbContext2里用Attach()还是Entry(entity).State = EntityState.Unchanged这类方式附加实体,本质都是把这个实例纳入dbContext2的缓存,后续查询都会复用它。但无论如何,dbContext1和dbContext2的缓存不会共享实例,所以两边的实体引用永远不会相等。
内容的提问来源于stack exchange,提问作者mxscho

