实体框架二级包含在预测中

时间:2012-07-21 15:59:33

标签: entity-framework linq-to-sql

我想在单个查询中检索一组对象(A)和一些相关对象(B)。 AB上没有导航属性,所以我相信我需要使用这种语法:

select a from db.As where a.Id = x select new AndBHolder
{
   A = a,
   Bs = select b from db.Bs where b.ASomeId == A.SomeId select b
}

我不确定这是否是最佳方式,但它确实有效。但是,我现在需要包含B的属性(Cs列表)。我没想到它会起作用,但我试过了:

select a from db.As where a.Id = x select new AndBHolder
{
   A = a,
   Bs = select b from db.Bs.Include("Cs") where b.ASomeId == A.SomeId select b
}

哪个失败,“方法...在类型上声明包含...不能使用类型的实例调用...”。接下来我想我会在投影中尝试投影:

select a from db.As where a.Id = x select new AndBHolder
{
   A = a,
   Bs = select b from db.Bs where b.ASomeId == A.SomeId select new B
        {
           Id = b.Id,
           // ...
           Cs = select c from db.Cs where c.BId == b.Id select c
        }
}

失败的“实体或复杂类型'B'无法在LINQ to Entities查询中构造”因为您不允许投影到映射对象中。那么如何在填充Bs的情况下检索Cs,或者不支持二级包含?我是否只需要对数据库进行两次调用,一次是检索As,另一次是使用Bs检索Cs

1 个答案:

答案 0 :(得分:3)

如果您使用select new投影,则无法再使用Include,它将被忽略。相反,您必须将相关实体添加到投影数据中,例如:

var query = from a in db.As
            join b in db.Bs on a.SomeId equals b.ASomeId into bGroup
            where a.Id = x
            select new AndBHolder
            {
                A = a,
                Bs = bGroup, // Bs must be of type IEnumerable<B>
                Cs = bGroup.SelectMany(bg => bg.Cs) // Cs is IEnumerable<C>
            };

如果BC之间的关系是一对多(不是多对多),EF应该在每个加载的Cs中填充B集合自动(称为“关系修正”),这意味着在从数据库加载数据后,您可以从投影中丢弃Cs。要将它们组合在一起,您可以尝试编写查询,如下所示:

var query = (from a in db.As
             join b in db.Bs on a.SomeId equals b.ASomeId into bGroup
             where a.Id = x
             select new
             {
                 A = a,
                 Bs = bGroup,
                 Cs = bGroup.SelectMany(bg => bg.Cs)
             })
             .AsEnumerable() // DB query gets executed here
             .Select(y => new AndBHolder
             {
                 A = y.A,
                 Bs = y.Bs // the Cs in every B should be populated here
             });