为什么LINQ with Lazy Loading会随机加载孩子?

时间:2014-12-12 20:09:47

标签: c# linq linq-to-sql entity-framework-4

我正在尝试加载具有一系列MyObjectChild对象的MyObject。默认情况下,我的上下文对象启用了LazyLoading,并且我没有禁用它。我的代码中有以下查询:

    public MyObject GetMyObject(string objectNumber)
    {
        List<MyObject> query = (from obj in Context.MyObjects
                                where obj.ObjectNumber == objectNumber
                                orderby obj.LastUpdateDate descending
                                select obj).ToList();

        return query.FirstOrDefault();
    }

这会将第一个项目作为对象返回。是的,我们想要断开从数据库返回的对象,所以我希望这会返回附加了所有MyObjectChild对象的MyObject。尴尬的部分是数据库有 MyObjectChild 的thouasands,但是在蓝色的月亮中它决定不加载它们。

稍后在代码中,我有:

    MyObject myObject = GetMyObject("123456");

    foreach (MyObjectChild c in myObject.MyObjectChilds)
    {
        ... /* Do some stuff */
    }

非常随意(一百次中的一次)这个foreach循环没有任何记录到&#34; foreach&#34;过度。请注意,它也不会抛出异常!!它完全绕过了代码的这一部分,就像MyObjectChilds集合是空的一样。

1)任何人都可以解释为什么会发生这种情况吗? 99%的时间,它完美无缺,但是当它失败时,对我们来说非常糟糕。我需要了解这可能会失败的条件,以便我可以围绕它进行编码。

2)防止这种情况/条件的最佳方法是什么?我们在各地都做这种事情,我们的数据库布局很大,所以我不想关闭延迟加载并且必须重写所有底层代码以在整个地方使用数千个.Include(...)语句。是否有更好/更容易/更快的解决方案仍然保证我们每次都能获得信息?

更新

经过多次挖掘后,我发现了两个&#34;半简单&#34;这个问题的解决方案。我所知道的,但却被忽视了:ToList()。是的,我在查询中执行ToList(),但我没有在foreach上执行此操作,因此它有可能无法加载子对象。

    foreach (MyObjectChild c in myObject.MyObjectChilds.ToList())
    {

另一个与.ToList()类似的 MUCH 的解决方案是在每次使用之前强制加载子对象。这对我来说实施起来要麻烦得多(基于我目前的代码)。但是,(从我在SO周围的其他帖子中可以看出),这更有可能总是得到我正在寻找的结果。

    if (!obj.MyObjectChilds.IsLoaded)
    {
        obj.MyObjectChilds.Load();
    }
    foreach (MyObjectChild c in myObject.MyObjectChilds)
    {
        ...

现在,我正在浏览我的代码,以确保我ToList - 编辑了遍历子数据库对象的所有foreach循环。这似乎是最简单的修复方法,虽然我不确定它是否是最正确的&#34;固定。

2 个答案:

答案 0 :(得分:0)

所以我之前遇到过同样的问题。关键是尽快收到你的初始收藏品。

一旦检测到这一点,您就需要重新加载子集合。

这是一种帮助解决此问题的扩展方法。

public static void RefreshChildCollections<TEntity, TContext>(this ICollection<TEntity> entityCollection, TContext content)
{
    ((IObjectContextAdapter)content).ObjectContext.Refresh(RefreshMode.StoreWins, entityCollection);
}

用法

collectionToReload.RefreshChildCollections(Context);

答案 1 :(得分:0)

ToList()将执行查询并创建无法加载子项的数据的本地副本。但要100%确定将使用Include方法加载子项。另外我建议你重写你的查询(使用FirstOrDefault而不是ToList并手动复制你的对象(使用Clone方法))。要检查MyObjectChild是否已加载,请使用IsLoaded并手动加载子项使用Load方法。