如何在 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 这样的东西,但如果可能的话,我希望它是公平的有点复杂,以后可能难以修改和理解。
给定'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 这样的东西,但如果可能的话,我希望它是公平的有点复杂,以后可能难以修改和理解。