如何在 Entity Framework Core 中获得孙子

How to get grandchild in Entity Framework Core

给定'parentItemNo'时如何显示children和grandchildren

下面是我的模型:任何记录 (itemNo) 都可以变成 parent、child 或 grandchild.

public partial class item
{      
    public string ItemNo { get; set; }         
    public string ParentItemNo { get; set; }     
}

以下查询returns children: 也想显示grandchildren。

 var result = Context.Items.Where(p => p.ParentItemNo == parentItemNo).Select(p => p.ItemNo).ToListAsync(); ;

导航属性。

给定一个项目 class,它可以有多个级别,其中每个项目可以有一个可选的 Parent:

public class Item
{
    [Key]
    public string ItemNo { get; set; }
    [ForeignKey("Parent")]
    public string ParentItemNo { get; set; }
    public virtual Item Parent { get; set; }
    public virtual ICollection<Item> Children { get; set; } = new List<Item>();
}

从这里开始,我建议在 DbContext OnModelCreating 事件中或使用 EntityTypeConfiguration 实现显式设置映射:

modelBuilder.Entity<Item>()
    .HasOptional(x => x.Parent)
    .WithMany(x => x.Children);

当你想获得一个物品的 children 和 grand-children 时:

var children = await context.Items
    .Include(x => x.Children) // eager load children
        .ThenInclude(x => x.Children) // eager load grandchildren
    .Where(x => x.ItemNo == parentItemNo)
    .SelectMany(x => x.Children)
    .ToListAsync();

通常情况下,尽管您会加载 parent,但它是 children 和 grandchildren 急切加载的:

var parent = await context.Items
    .Include(x => x.Children)
        .ThenInclude(x => x.Children)
    .SingleAsync(x => x.ItemNo == parentItemNo);

对于预先加载,您需要提前计划您期望需要的数据,否则您应该确保延迟加载已启用并且可用,如果 grandchild 本身可能有 child仁项目。迭代到这个级别将尝试延迟加载(如果 object 从它的 DbContext 中孤立出来,可能会导致错误)或 return 没有数据或数据的部分表示,如果 DbContext 已经跟踪一些可以填写的曾祖children

编辑:如果您只想获取 children 和 grandchildren 的商品编号,则无需使用 Include 预加载那将是 return 实体及其相关实体。使用 Select / SelectMany 的投影不需要这个。

到select任何Children和Grandchildren的ItemNos:

var childDetails = await context.Items
    .Where(x => x.ItemNo == parentItemNo)
    .SelectMany(x => x.Children.Select(c => new 
    {
        c.itemNo,
        GrandChildItemNos = c.Children.Select(gc => gc.itemNo).ToList()
    }).ToListAsync();

这将为您提供一个匿名类型列表,其中包含每个 child 的项目编号,以及 child 的大 child 项目编号的列表。从那里您可以组合所有项目 #s:

List<string> itemNumbers = childDetails.Select(x => x.itemNo).ToList();
foreach(var child in childDetails)
    itemNumbers.AddRange(child.GrandChildItemNos);

这会将 children 和他们的祖父 children 的所有项目编号合并到一个列表中。从那里,如果与特定 child 的关系可以加倍(2 children 共享同一个 grandchild),您可以在末尾添加 Distinct() 以删除重复项。

有可能在 EF Linq 操作中 select child 和 grand child 使用像 Union 这样的东西,但如果可能的话,我希望它是公平的有点复杂,以后可能难以修改和理解。