已知父/子分类ID时如何查询所有关联父子分类及对应商品
问题分析
你现有代码models = models.Where(i => i.Category.SubCategories.Select(i => i.Id).Contains(catid));的逻辑是匹配「商品所属分类的直接子分类ID包含目标catid」的商品,既没有覆盖目标分类自身、所有层级的递归子分类,逻辑方向也和需求不符,因此结果不符合预期。
实现方案
根据你的两个需求,优先提供适配中小数据量的内存递归方案,分类数据量极大的场景可以替换为数据库层面的递归CTE方案。
第一步:提前写好两个递归工具方法
注:如果你的实体类ID属性是大写Id,请对应调整代码中的属性名
// 递归获取指定分类ID的自身 + 所有子孙分类ID private IEnumerable<long> GetAllSubCategoryIds(long catId, List<Category> allCategories) { var result = new List<long> { catId }; var childIds = allCategories.Where(c => c.ParentId == catId).Select(c => c.id).ToList(); foreach (var childId in childIds) { result.AddRange(GetAllSubCategoryIds(childId, allCategories)); } return result; } // 递归获取指定分类ID的自身 + 所有祖先分类ID private IEnumerable<long> GetAllParentCategoryIds(long catId, List<Category> allCategories) { var result = new List<long> { catId }; var currentCat = allCategories.FirstOrDefault(c => c.id == catId); while (currentCat?.ParentId != null) { result.Add(currentCat.ParentId.Value); currentCat = allCategories.FirstOrDefault(c => c.id == currentCat.ParentId.Value); } return result; }
需求1:按指定分类ID查询自身+所有子分类下的全部商品
// 先全量加载分类数据(分类量级过万的场景建议替换为CTE方案) var allCategories = dbContext.Categories.ToList(); // 拿到所有需要匹配的分类ID var targetCatIds = GetAllSubCategoryIds(catid, allCategories).Distinct().ToList(); // 过滤商品 models = models.Where(p => p.CategoryId.HasValue && targetCatIds.Contains(p.CategoryId.Value));
需求2:按子分类ID查询所有上级父分类+下级子分类的关联数据
var allCategories = dbContext.Categories.ToList(); // 合并祖先和后代分类ID var parentIds = GetAllParentCategoryIds(childCatId, allCategories); var subIds = GetAllSubCategoryIds(childCatId, allCategories); var allRelatedCatIds = parentIds.Union(subIds).Distinct().ToList(); // 过滤对应关联商品即可 models = models.Where(p => p.CategoryId.HasValue && allRelatedCatIds.Contains(p.CategoryId.Value));
大数据量场景优化(以SQL Server为例)
如果分类量级过万,内存递归性能较差,可以直接用递归CTE查询,性能更高:
var products = dbContext.Products.FromSqlInterpolated($@" WITH RecursiveCte AS ( SELECT id FROM Categories WHERE id = {catid} UNION ALL SELECT c.id FROM Categories c INNER JOIN RecursiveCte rc ON c.ParentId = rc.id ) SELECT p.* FROM Products p INNER JOIN RecursiveCte rc ON p.CategoryId = rc.id ").ToList();
内容的提问来源于stack exchange,提问作者nabi mohammadi
相关产品推荐
相关产品推荐

