加载后导航属性未完全加载
本文关键字:加载 属性 导航 | 更新日期: 2023-09-27 18:08:38
我使用如下代码来选择一个大的对象列表,用于只读目的:
using (DBContext db = new MyContextClass())
{
... data creation ...
db.SaveChanges();
}
using (DBContext db = new MyContextClass())
{
db.Configuration.LazyLoadingEnabled = false;
db.Configuration.ProxyCreationEnabled = false;
db.Configuration.AutoDetectChangesEnabled = false;
DbQuery data = db.Set(someType)
foreach (string propertyName op in somePropertieNames)
data = data.Include(propertyName);
foreach (object item in data.AsNoTracking())
ScanNavigatorsOf(item);
}
在ScanNavigatorsOf()
中,我阅读了所有的导航属性,我注意到foreach
循环产生的第一个对象具有不完整的集合和引用。似乎导航属性的填充在程序点击我的ScanNavigatorsOf(...)
方法时还没有完成。所有其他对象都有完整的导航属性。我正在运行单元测试,所以我可以确保对象很好地存储在数据库中。
如何等待加载对象的导航集合和引用被完全填充?
就像ObjectContext中解释的那样。ObjectMaterialized事件,集合似乎没有在主对象的同时物化,但是我怎么知道这个过程什么时候完成?
我很确定你正在经历关闭DetectChanges
的副作用。这是EF在表面下多次调用,以确保已正确建立跟踪实体之间的所有关联,并与原始外键值匹配(这称为关系修复)。也许你有理由关掉它,但正如莱曼&Miller在他们的书DbContext:
确定何时需要调用DetectChanges并不像它那么简单可能会出现。实体框架团队强烈建议您如果您遇到以下情况,请切换到手动调用DetectChanges性能问题。还建议只选择退出自动检测执行不佳的代码部分的更改并重新启用它
在此之上,您无需跟踪即可获取对象。现在EF在关联方面几乎完全瘫痪了。
你应该让DetectChanges
完成它的工作,或者在循环中调用它。并且启用跟踪,否则更改跟踪器无法修复关联。
foreach (object item in data)
{
db.ChangeTracker.DetectChanges();
ScanNavigatorsOf(item);
}
或者在ScanNavigatorsOf
中触发DetectChanges
的方法之一将运行时,在循环运行之前打开AutoDetectChangesEnabled
。
但是在AsNoTracking
中还有另一个问题。关闭更改跟踪的效果是上下文不能作为身份映射,这意味着:它不能确保数据库中的每条记录将被精确地具体化一次。
如果在Includes
中有一个1-n-1
关联,比如Order-OrderLine-Product
,那么不需要跟踪每个OrderLine
,就会创建一个新的Product
实例,即使"相同"的产品已经为上一个订单线创建了。这不是一个大问题,只要你使用的数据是只读的,但一旦你要把它们附加到上下文(例如复制),你会遇到重复键异常。
简而言之:当关联重要时,让变更跟踪器完成它的工作,并确保及时调用DetectChanges
。