How can I re-write my query to include all the products of each category in a recursive product category tree? This query gets the categories and their children, so I'm just missing the products:
var categories = _context.ProductCategories
.Include(e => e.Children)
.Where(e => e.ParentId == null)
.ToList();
Entity models:
public class ProductCategory
{
public int Id { get; set; }
public int SortOrder { get; set; }
public string Title { get; set; }
[ForeignKey(nameof(ParentCategory))]
public int? ParentId { get; set; }
// Nav.props:
public ProductCategory ParentCategory { get; set; }
public ICollection<ProductCategory> Children { get; set; }
public List<ProductInCategory> ProductInCategory { get; set; }
}
public class ProductInCategory
{
public int Id { get; set; }
public int ProductId { get; set; }
public int SortOrder { get; set; }
public int ProductCategoryId { get; set; }
// Nav.props:
public Product Product { get; set; }
public ProductCategory ProductCategory { get; set; }
}
public class Product
{
public int Id { get; set; }
public string Title { get; set; }
public string Info { get; set; }
public decimal Price { get; set; }
// Nav.props:
public List<ProductInCategory> InCategories { get; set; }
}
Viewmodel:
public class ViewModelProductCategory
{
public int Id { get; set; }
public int? ParentId { get; set; }
public string Title { get; set; }
public int SortOrder { get; set; }
public string ProductCountInfo
{
get
{
return Products != null && Products.Any() ? Products.Count().ToString() : "0";
}
}
public ViewModelProductCategory ParentCategory { get; set; }
public IEnumerable<ViewModelProductCategory> Children { get; set; }
public IEnumerable<ViewModelProduct> Products { get; set; }
}
I'm using AutoMapper to convert the query result to viewmodel.
Here is how I'm attempting to render:
Index-view:
@model IEnumerable<MyStore.Models.ViewModels.ViewModelProductCategory>
<ul style="list-style:none;padding-left:0px;">
@Html.Partial("_CategoryAndProductRecursive", Model)
</ul>
_CategoryAndProductRecursive.cshtml:
@model IEnumerable<MyStore.Models.ViewModels.ViewModelProductCategory>
<ul>
@if (Model != null)
{
foreach (var item in Model)
{
<li>
@item.Title
<ul style="list-style:none;">
@Html.Partial("_CategoryAndProductRecursive.cshtml", item.Children)
@if (item.Products != null)
{
@foreach (var product in item.Products)
{
<li>@product.Title</li>
}
}
</ul>
</li>
}
}
</ul>
答案 0 :(得分:2)
EF Core查询部分实际上有两个独立的问题。
首先是如何热切加载ProductCategory.ProductInCategory
和ProductInCategory.Product
导航属性。答案很简单 - 使用Include
/ ThenInclude`,如文档的Loading Related Data - Eager Loading 部分所述。
第二个是如何递归ProductCategory.Children
。诀窍是强制在内存中加载整个 ProductCategory
树,从而让EF Core导航属性修复进行父/子实体链接,然后然后过滤根实体。
var categories = _context.ProductCategories
.Include(e => e.ProductInCategory)
.ThenInclude(e => e.Product)
.AsEnumerable() // <-- Force full execution (loading) of the above
.Where(e => e.ParentId == null) // <-- then apply the root filter
.ToList();
请注意,我们不需要在此过程中加入Children
。请注意,有些Children
个集合将为null
。如果这是一个问题,请确保在构造函数或初始化程序中初始化它们。
public ICollection<ProductCategory> Children { get; set; } = new List<ProductCategory>();
答案 1 :(得分:0)
你可以尝试使用Load而不是Include并循环预定次数来每次加载孩子。