在急切加载后导航属性未完全加载

时间:2014-06-15 16:10:42

标签: c# .net entity-framework entity-framework-6

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 对象同时具体化,但我怎么知道该进程何时完成?

2 个答案:

答案 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