【问题标题】:LINQ query to get recursive category structure and products of each categoryLINQ查询以获取递归类别结构和每个类别的产品
【发布时间】:2018-02-03 21:45:30
【问题描述】:

如何重新编写查询以将每个类别的所有产品包含在递归产品类别树中?此查询获取类别及其子项,因此我只是缺少产品:

var categories = _context.ProductCategories
                .Include(e => e.Children)
                .Where(e => e.ParentId == null)
                .ToList();

实体模型:

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; }
}

视图模型:

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; }
}

我正在使用 AutoMapper 将查询结果转换为视图模型。

这是我尝试渲染的方式:

索引视图:

@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>

【问题讨论】:

    标签: c# linq recursion entity-framework-core


    【解决方案1】:

    EF Core 查询部分实际上有两个独立的问题。

    首先是如何预先加载ProductCategory.ProductInCategoryProductInCategory.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>();
    

    【讨论】:

    • 我刚刚意识到您的解决方案只返回第一代产品。未找到儿童儿童类别中的任何产品。
    • 异步怎么样,我猜初始加载部分可以异步,例如var allCategories = await _context.ProductCategories.Include(...).ThenInclude(...).ToListAsync(); return Mapper.Map&lt;List&lt;ViewModelProductCategory&gt;&gt;(allCategories.Where(e =&gt; e.ParentId == null);
    • 如果您的意思是产品仅在它们所连接的级别加载(无论深度如何),这是正确的。但是您始终可以使用我的 Expand 方法(或任何类似方法)从 How to flatten tree via LINQ? 获得每个级别的所有直接和间接产品
    • 在我的系统中只能有叶级别的产品。但我希望它们在查看整个展开的树时可见。
    【解决方案2】:

    您可以尝试使用 Load 而不是 Include 并循环预定义次数以每次加载子项。

    https://msdn.microsoft.com/en-us/library/bb896249.aspx

    【讨论】:

      猜你喜欢
      • 2021-03-12
      • 1970-01-01
      • 2021-02-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-15
      • 1970-01-01
      • 2021-07-11
      相关资源
      最近更新 更多