【问题标题】:Linq query which retrieved parent/child of children with a collectionLinq 查询使用集合检索子项的父/子
【发布时间】:2014-12-09 13:00:40
【问题描述】:

我有一个自引用的Category 类,如果它在集合中至少有一个子类别并且至少有 1 个或多个活动 (ICollection<Activity>),我想从中检索父类别和所有对应的子类别。

这也适用于孩子的孩子,因为只有当孩子类别至少有 1 个或更多活动时才应返回这些。

如果没有包含至少 1 个或多个活动的子类别,则应返回父或子 Category

查询应该将父 Category 作为实际的 Category 对象返回,而不仅仅是 CategoryId。这可能吗?

public class Category
{
    public int CategoryId { get; set; }
    public string Name { get; set; }
    public int? ParentId { get; set; }
    public virtual Category Parent { get; set; }

    public virtual ICollection<Category> Children { get; set; }
    public virtual ICollection<Activity> Activities { get; set; }
}

更新 1

部分有效的查询:

 var categories = _db.Categories
        .Where(x => x.Parent != null &&  x.Activities.Count > 0)
        .GroupBy(x => x.ParentId)
        .Select(g => new { Parent = g.Key, Children = g.ToList() }).ToList();

【问题讨论】:

  • 您尝试过的查询在哪里?
  • 您存储ParentId的任何特殊原因?你不会从Parent.CategoryId 那里得到这个吗?
  • @RufusL 这在 EF 中很典型,因此您可以将一行作为一个实体拉出,而无需实际拉出引用的实体。你得到链接到父对象的 id,但不是父对象。
  • 对于给定的实例,父母说,4 个孩子,只有 1 个满足条件。选择父母是否意味着将自动选择所有孩子?
  • @P.K.你怎么知道可能的许多子孩子中的一个满足条件?如果是这样,你怎么知道只有父母回来的?您有示例 linq 查询吗?

标签: c# sql linq entity-framework


【解决方案1】:

让我们从小一点开始,因为您要创建的查询有些复杂。我们将自下而上创建您的查询。首先,您要消除没有任何子类别且至少有一个或多个活动的类别。让我们创建一个 Predicate 以返回 true 用于应该包含的那些和 false 用于应该排除的那些,在一个级别上。我们将分两个阶段进行。首先,让我们为具有活动的类别创建一个返回 true 的谓词:

Predicate<Category> hasActivities = cat => cat.Activities.Any();

其次,让我们创建一个Predicate 以返回true 用于具有活动的子类别的那些类别:

Predicate<Category> hasChildWithActivities = 
    parentCat => parentCat.Children.Any(hasActivities);


现在让我们创建过滤器查询,它将过滤给定的Category 的后代。为此,我们将创建一个Func,它接受父Category,执行逻辑并返回更新后的Category

Func<Category, Category> getFilteredCategory =
    parentCat => 
    {
        parentCat.Children = parentCat.Children
            .Where(hasChildWithActivities)
            .Select(getFilteredCategory);

        return parentCat;
    });

请注意,这相当于:

Func<Category, Category> getFilteredCategory = delegate(Category parentCat)
{
    parentCat.Children = parentCat.Children
        .Where(hasChildWithActivities)
        .Select(getFilteredCategory);

    return parentCat;
};


在您的 OP 中,您提到您也想过滤父母。您可以通过遍历到顶层并运行此查询,或者通过使用“joins”或更复杂的“select”语句创建单独的查询,在父级上使用相同的逻辑。恕我直言,后者可能会很混乱,我建议不要这样做。如果您还需要将逻辑应用于父级,则首先遍历树。不管怎样,这应该会给你一个好的开始。


如果您有任何问题,请告诉我。祝你好运,编码愉快! :)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-02-12
    • 2021-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多