Linq过滤树

时间:2017-02-08 07:40:32

标签: c# .net linq

班级结构

public clas Item 
{
   public Item Parent { get; set; }

   public string Code { get; set; }
}

示例树

AAA
 - AAB
    - BBB
CCC
 - CCA

所以我想通过CODE == BBB过滤树,结果应该是

AAA
 - AAB
    - BBB

但如果我像这样过滤

IQueryable<Item> itemsQuery = GetQuery();
itemsQuery = itemsQuery.Where(x => x.Code == "BBB")

结果不包含父节点。那么,如果子节点满足某些条件,如何包含父节点?

3 个答案:

答案 0 :(得分:0)

简单来说,使用EF无法获得递归树。 EF返回平面集合。但是,有一些解决方法。

变式1:

添加到您的商品public Item Root { get; set; }public ICollection<Item> AllSiblings { get; set; }属性,它将所有商品指向实际的根,第二个是另一种方式(所有嵌套商品)。

查询比看起来像:

IQueryable<Item> itemsQuery = GetQuery().Include(x => x.AllSiblings);
itemsQuery = itemsQuery.Where(x => x.Code == "BBB" || x.AllSiblings.Any(s => s.Code == "BBB")).ToList();

现在你的应用程序中有所有项目,你可以递归地在C#中创建树。

变体2:

您可以进行多次SQL查询以获取找到的项目的每个父项。不建议这样做,因为在更多找到的结果上它会变慢。

答案 1 :(得分:0)

这里很难应用LinQ,因为没有从父项到子项的引用。在应用过滤器后对父进行简单枚举怎么办?它将为您提供树中所有匹配项的列表,然后您可能需要以“树”方式打印它。这是一个BFS示例

        IQueryable<Item> itemsQuery = items.AsQueryable();
        itemsQuery = itemsQuery.Where(x => x.Code == "BBB");

        var bfsQueue = new Queue<Item>(itemsQuery);
        var matchedItemsSet = new HashSet<Item>();

        while (bfsQueue.Count > 0) {
            var item = bfsQueue.Dequeue();
            matchedItemsSet.Add(item);

            var parent = item.Parent;
            if (parent != null && !matchedItemsSet.Contains(parent))
            {
                bfsQueue.Enqueue(parent);
            }
        }

        foreach (var item in matchedItemsSet) {
            Console.WriteLine(item.Code);
        }

答案 2 :(得分:0)

我更喜欢通用方法。

public static IEnumerable<T> SelectUntil<T>(this T element, Func<T, T> nextMemberSelector, Func<T, bool> stopCondition)
{
    while (!stopCondition(element))
    {
        yield return element;
        element = nextMemberSelector(element);
    }
}
public static IEnumerable<Item> GetAncestors(this Item e)
{
    // Or don't Skip(1) if you need the child itself included.
    return e.SelectUntil(T => T.Parent, T => T.Parent == null).Skip(1);
}

private static void Main(string[] args)
{
    IEnumerable<Item> itemsQuery = GetQuery();
    IEnumerable<Item> filter = itemsQuery.Where(T => T.Code == "BBB");

    foreach (Item item in filter)
    {
        Item[] allParents = item.GetAncestors().ToArray();
    }

}