选择具有多个和嵌套级别的实体,而不使用Include

Mar*_*arc 4 c# linq entity-framework

我有以下实体:

public class Item 
{
    public int Id { get; set; }

    public int? ParentId { get; set; }
    public Item Parent { get; set; }
    public List<Item> Children { get; set; }

    public double PropertyA { get; set; }
    public double PropertyB { get; set; }
    ...
}
Run Code Online (Sandbox Code Playgroud)

现在我想查询数据库并检索所有嵌套子节点的数据.我可以通过使用Eager Loading来实现这一点Include():

var allItems = dbContext.Items
                    .Include(x => Children)
                    .ToList();
Run Code Online (Sandbox Code Playgroud)

但是,我想做以下投射,而不是Eager Loading:

public class Projection 
{
    public int Id { get; set; }
    public List<Projection> Children { get; set; }
    public double PropertyA { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

是否可以通过一次选择仅检索所需的数据?我们正在使用Entity Framework 6.1.3.

编辑: 这是我到目前为止所尝试的.我真的不知道如何告诉EF以Projection比他们父母相同的方式映射所有孩子.

EntityFramework.SqlServer.dll中出现未处理的"System.NotSupportedException"类型异常

附加信息:"Projection"类型出现在单个LINQ to Entities查询中的两个结构不兼容的初始化中.A型可以在同一个查询两个地方被初始化,但只有当同一属性在两个地方设置和这些属性以相同的顺序设置.

var allItems = dbContext.Items
    .Select(x => new Projection
    {
        Id = x.Id,
        PropertyA = x.PropertyA,
        Children = x.Children.Select(c => new Projection()
        {
            Id = c.Id,
            PropertyA = c.PropertyA,
            Children = ???
        })
    })
    .ToList();
Run Code Online (Sandbox Code Playgroud)

gre*_*k40 5

一般来说,您无法在单个SQL查询中加载未知无限深度的递归结构,除非您批量加载所有可能相关的数据,无论它们是否属于所请求的结构.

因此,如果您只想限制已加载的列(排除PropertyB),但可以加载所有行,结果可能如下所示:

var parentGroups = dbContext.Items.ToLookup(x => x.ParentId, x => new Projection
{
    Id = x.Id,
    PropertyA = x.PropertyA
});

// fix up children
foreach (var item in parentGroups.SelectMany(x => x))
{
    item.Children = parentGroups[item.Id].ToList();
}
Run Code Online (Sandbox Code Playgroud)

如果要限制已加载的行数,则必须接受多个数据库查询才能加载子条目.例如,加载单个子集合可能看起来像这样

entry.Children = dbContext.Items
    .Where(x => x.ParentId == entry.Id)
    .Select(... /* projection*/)
    .ToList()
Run Code Online (Sandbox Code Playgroud)