EF 5.0数据库优先,POCO类型和延迟加载



我不是一个DB的家伙,我对EF很陌生。我对FK关系上的延迟加载的不稳定行为感到困惑。

假设我有一个父表和一个子表。child在Parent中有一个非唯一的FK。现在一些代码:

Parent GetParent(int parentId)
{
    return Entities.Parents.Single(p => p.ParentId == parentId);
}
Child GetChildByName(int parentId, string name)
{
    var parent = GetParent(parentId);
    return parent.Children.Single(c => c.Name == name);   
}

现在,有时对parent.Children.Single的调用会失败,因为序列Parent.Children是空的。不是总是,而是有时,这让人非常沮丧。当它确实失败时,我已经通过Intellitrace验证了没有SQL调用来获取Children已经执行。

这个关系已经在数据库中正确创建,并且所有输入参数都是正确的。如果我使用Include("Children")并急切地加载所有的Children,它当然每次都能工作。

如果我在获得Parent之后,但在过滤Child之前抛出Thread.Sleep(1000),则Children通常会被加载并且调用成功。

所以,据我所知,这是一个与时间有关的问题。FK关系不是按需加载的,而是在看似任意的时间加载的。我不明白这种行为,我想我一定错过了什么。

我真的不想在任何地方添加Include("SomeFK"),因为它使我的代码更脆弱,真的,为什么我必须这样做?如果我必须在所有地方调用Include

A)抓取我经常不需要的数据B)编写我必须在添加或删除关系时进行编辑的代码C)没有从我的ORM中获得太多(除了琐碎的代码生成)。此时,我也可以编写原始的SQL调用。

所以,是的,我一定错过了一些东西,但我已经看过了,并没有能够找到一个全面的解释延迟加载使用POCO类型(数据库优先!)EF.

我想知道这是否与您在Parent方法中的Entities对象有关。可能是实体对象被处置或不可用,这样,当父对象被抓取时,子对象不是因为实体在延迟加载之前被处置?

我建议使用这样的代码模式来获得显式加载的对象,如果你要在实体上下文的范围之外检索它们。否则,随着上下文的消失,对象将无法延迟加载?这不是100%,但这就是为什么我总是显式加载时,我返回的记录没有DbContext对象可用。

好吧,这是我自己愚蠢的错误。当然,错误是在我的代码中,而不是成千上万的开发人员使用的库。

我在问题中没有提供足够的信息。我将省略次要的细节,但根本原因是竞争条件。

我正在通过线程a上创建的上下文创建/加载实体对象,然后它们被传递给函数,这些函数会创建一个新线程(B)并做它们的事情。对navigation属性的调用最终在线程b上执行。

从阅读文档中可以清楚地看出上下文不是线程安全的。从我收集到的信息来看,EF在创建上下文的线程上执行延迟加载,即线程a。

这就是为什么Thread.Sleep()似乎"修复"了这个问题;线程B空闲一秒钟,而主线程有机会填充导航属性。

在我们的代码中,主线程在调用异步函数后忙于执行一堆UI更新,所以它阻止了上下文做它的事情。同步执行所有操作都很好。

希望这对将来遇到类似情况的人有所帮助。正如那句老话所说,RTFM。

最新更新