lI使用类似这样的代码来选择大型对象列表,仅供参考:
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 Event中解释的一样,这些集合似乎没有与 main 对象同时具体化,但我怎么知道该进程何时完成?
答案 0 :(得分:0)
首先使用ToList()
加载所有数据,然后扫描导航属性:
var queryableData = db.Set(someType).AsNoTracking();
var data = somePropertieNames.Aggregate(queryableData , (current, property) => current.Include(property)).ToList();
foreach (object item in data)
ScanNavigatorsOf(item);
答案 1 :(得分:0)
我很确定你会遇到关闭DetectChanges
的副作用。这是EF在表面下方建立many times的调用,以确保已正确建立跟踪实体之间的所有关联并与原始外键值匹配(这称为 relationship fixup )。您可能有理由将其关闭,但作为Lerman&米勒在他们的书 DbContext :
需要调用DetectChanges时的工作并不像它那样简单 可能会出现。实体框架团队强烈建议您 如果您遇到,只能交换到手动调用DetectChanges 性能问题。它也建议只选择退出自动 检测代码表现不佳的部分并重新启用它 一旦有关部分完成执行。
除此之外,您还可以在不跟踪的情况下获取对象。现在EF在协会方面几乎完全瘫痪了。
你应该让DetectChanges
完成它的工作,或者在循环中调用它。并启用跟踪,否则更改跟踪器无法修复关联。
foreach (object item in data)
{
db.ChangeTracker.DetectChanges();
ScanNavigatorsOf(item);
}
或者在循环运行之前启用AutoDetectChangesEnabled
,在ScanNavigatorsOf
中,其中一个触发DetectChanges
的方法将会运行。
但AsNoTracking
还有另一个问题。关闭更改跟踪的效果是上下文不能用作身份映射,这意味着:它无法确保数据库中的每条记录只能实现一次。
如果您的1-n-1
中存在Includes
关联,请说Order-OrderLine-Product
,而无需跟踪每个OrderLine
,即会创建新的Product
实例,甚至如果已经为之前的订单行创建了“相同”的产品。只要您使用只读数据,这不是一个大问题,但只要您将它们附加到上下文(例如,用于复制),您就会遇到重复的密钥异常。
简而言之:当关联很重要时,让更改跟踪器完成其工作并确保及时调用DetectChanges
。