CSharp - 为什么 LINQ LazyLoading随机加载子进程?

  显示原文与译文双语对照的内容
0 0

我正在尝试加载 MyObject,它有一系列MyObjectChild对象。 默认情况下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对象。 令人尴尬的部分是数据库有 MyObjectChild,但在蓝色月亮中,它决定不加载它们。

在代码的后面,我有:

 MyObject myObject = GetMyObject("123456");
 foreach (MyObjectChild c in myObject.MyObjectChilds)
 {
. . ./* Do some stuff */
 }

这个foreach循环没有任何记录可以通过它。 请注意,它也不会引发异常 ! 它完全绕过了代码的这一部分,就好像MyObjectChilds集合是空的一样。

1 ) 任何人都可以解释为什么这样发生? 这是一个很好的工作,但是当它失败时,对我们来说是非常坏。 我需要了解在什么情况下这可能失败,这样我就可以编写它。

2 ) 什么是防止这种情况发生的最佳方法/条件? 但是我们在整个地方做这种事情,数据库布局很大,所以我宁愿把所有的底层代码都写下来,然后重写所有的底层代码来使用整个代码。 是否还有 better/easier/faster 解决方案可以保证我们每次都能得到信息?

更新

在进行了更多挖掘之后,我发现了两个"半简单"解决方案。 一个我知道但只是忽略了: ToList() 。是的,我在查询上做一个 ToList(),但是我没有在 foreach 上做,因这里它有机会不加载子对象。

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

另一种解决方法是:像 .ToList() 那样,在每次使用之前强制加载子对象。 这对于我实现( 根据我目前的代码) 来说要麻烦得多。 但是,( 从我周围的其他帖子中可以看出) 更有可能总是有我正在寻找的结果。

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

目前,我正在检查代码以确保我的所有foreach循环都通过了sub-database-objects循环。 这似乎是最简单的修复,尽管我不确定这是"最正确"修复程序。

时间:原作者:7个回答

0 0

所以我以前也有同样的问题。 当你获得初始集合时,尽快检测它。

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

下面是一个帮助解决这个问题的扩展方法。

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

用法

collectionToReload.RefreshChildCollections(Context);
原作者:
0 0

ToList() 将执行查询并创建无法加载子级的本地数据副本。 但是要确保子节点将被加载,使用包括 。 另外,我还要recomend重写你的查询( 使用FirstOrDefault而不是 ToList,手动复制对象( 使用克隆方法) ) 。 要检查MyObjectChilds是否已经加载,请使用IsLoaded并手动加载子进程的负载方法。

原作者:
...