IQueryable <t> .Include()被忽略</t>

时间:2014-03-08 11:01:55

标签: c# .net linq entity-framework

我将ParentChild个实体相互关联为1到M.我需要在单个SQL查询中与父项一起查询子项,但Include方法不是在某些情况下正常工作。
这个对ParentChild表进行了正确的单一查询(通过JOIN):

var r1 =
    ctx.Set<Parent>()
       .Include(p => p.Childs)
       .Where(p => p.Id == 1)
       .ToList();

一旦我动态创建一个匿名对象,孩子们就会迷路,而SQL只包含Parent的字段。检索孩子仍然很懒 - 他们仍然没有加载:

var r2 =
    ctx.Set<Parent>()
       .Include(p => p.Childs)
       .Where(p => p.Id == 2)
       .Select(p => new { myParent = p})
       .ToList();

问题:

  1. 为什么会这样?
  2. 如何在LINQ中构建一个新的匿名对象,这样孩子们就不会丢失?
  3. P.S。我想保持Parent虚拟的Childs属性。

2 个答案:

答案 0 :(得分:4)

这是我所知道的所有EF版本的一般问题。 EF努力尽可能地传递'包含',但是当“查询的形状发生变化”时,'包含'会不可逆转地丢失。

例如,在以下情况下,查询的“形状”会发生变化:

  • 使用投影(选择不是整个对象,只选择一些字段或不同的对象)
  • 使用分组或其他聚合
  • ..可能在更多情况下,目前我不记得了。

可悲的是,我也不记得在MSDN上我偶然发现了“查询形状”的解释。如果我找到它,我会在这里放一个链接。

解决方案实际上非常简单:只是提前指定'include'部分,但最后结果。因此,开始时不要使用set.include(x),而是.Select( .. => new { .., x })手动包含“x”。它也适用于分组,因为你也可以在那里进行投影。

然而,这不是解决方案。这是一个手动补丁/修补程序,它无法解决任何问题。考虑到您可能想要公开“IQueryable&lt;&gt;”通过某种界面,您可能希望公开一些“基础查询”。已包含一些内容。当然,这只是不可能以一般方式进行,就像界面的客户端进行投影或分组一样,他将失去包含,他甚至不知道哪些应该是。对我来说,这是EF的一个主要缺陷。

编辑:刚刚找到一个:.Include in following query does not include really不是MSDN,但同样好。

答案 1 :(得分:0)

在您创建匿名对象时,上下文的Parent DbSet Set<Parent>()未填充任何数据,因此Child ren也未被存储在上下文中。一种解决方案可能是将子项添加到匿名对象,但我不确定这会将它们添加到Set<Child> DbSet

var r2 = ctx.Set<Parent>()
   .Include(p => p.Childs)
   .Where(p => p.Id == 2)
   .Select(p => new { myParent = p, children = p.Childs })
   .ToList();