2017-02-08 119 views
1

類結構LINQ到過濾樹

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

    public string Code { get; set; } 
} 

例如樹

AAA 
- AAB 
    - BBB 
CCC 
- CCA 

所以我想通過代碼來過濾樹== BBB和結果應該是

AAA 
- AAB 
    - BBB 

,但如果我像這樣的過濾器

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

結果不包含父節點。那麼,如果包含父節點,如果他們的子節點滿足某些條件?

+0

您需要頂部或只有一個的所有項目? – A3006

+0

目前尚不清楚AAA是否是AAB的母公司,反之亦然。 – Tomer

+0

你可以嘗試'itemsQuery.Where(x => x.Code ==「BBB」)。選擇(x => x.Parent)'或者甚至在你想創建一個結構時使用'new'關鍵字你的需要)。 –

回答

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查詢來獲得找到的項目每個父母。這是不推薦的,因爲它會發現更多的結果非常緩慢。

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

}