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

时间:2013-05-09 18:31:14

标签: c# entity-framework lazy-loading

我不是一个DB人,我对EF很新。我对FK关系中延迟加载的不稳定行为感到困惑。

假设我有一个表Parent和一个表Children。儿童对父母有非独特的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验证没有执行对fetch Children的SQL调用。

此关系已在数据库中正确创建,并且所有输入参数均正确无误。 如果我使用Include("Children")并急切地加载所有孩子,那么每次都会有效。

如果我在获得父级之后但是在我过滤子级之前抛出Thread.Sleep(1000),则子级将经常被加载并且调用成功。

因此,据我所知,这是与时间相关的问题。 FK关系没有按需加载,但它们正在看似随意加载。我不明白这种行为,我认为我必须遗漏一些东西。

我真的不想在任何地方添加Include("SomeFK")因为它会让我的代码变得更脆弱,而且,为什么我必须这样做呢?如果我必须在我所在的地方({1}}拨打电话

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

所以是的,我必须遗漏一些东西,但我看起来并且无法找到使用POCO类型(数据库优先!)延迟加载的全面解释。

2 个答案:

答案 0 :(得分:0)

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

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

答案 1 :(得分:0)

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

我没有在问题中提供足够的信息。我会忽略一些细节,但根本原因是竞争条件。

我正在通过在线程A上创建的上下文创建/加载实体对象。然后将它们传递给调整新线程(B)的函数并完成它们的操作。对导航属性的调用最终在线程B上执行。

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

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

在我们的代码中,主线程忙于在调用异步函数后立即执行一堆UI更新,因此它会阻止上下文执行其操作。同步执行所有操作都很正常。

希望这有助于某天遇到类似情况的人。正如古老的谚语所说,RTFM。