2012-11-08 171 views
1

想象一下當您有一個帶有用戶表的用戶時,我們的用戶具有分層結構的情況。分層數據和LINQ - 最佳實踐

[Key] 
public virtual int UserId { get; set; } 

public virtual UserProfile UserParent { get; set; } 
public virtual int? UserParentId { get; set; } 
public virtual String UserName { get; set; } 

放置在那裏的樣本數據:

用戶ID UserParentId用戶名

  • 1 | null |老闆
  • 2 | 1 |經理戴安娜
  • 3 | 2 |工人山姆
  • 4 | 2 |工人Bob
  • 5 | 1 |黃經理
  • 6 | 5 |工人路

爲每個用戶分配一個鏟:P

[Key] 
public virtual int ShovelId { get; set; } 

public virtual string ShovelSerialNumber { get; set; } 
public virtual int UserId { get; set; } 

放置在那裏的樣本數據:

ShovelId ShovelSerialNumbe用戶ID

  • 1 | 12345BK | 3
  • 2 | 99999ZK | 4
  • 3 | 88888KP | 6

所有這些的目的是獲取挖土機的序列號,在用戶表上進行分層查詢。老闆會看到所有的鏟子,但只有鏟子管理下屬員工。

關於如何在LINQ中實現這一點的任何想法和提示,考慮到可能有數千名員工和數千個鐵鍬,並且不知道抑鬱症等級的深度。

Thx尋求幫助。

+0

您已經使用ORM標籤,提示有涉及到數據庫,在這種情況下,所有分層的東西都應該在數據庫中完成。 LINQ無法真正表達分層查詢。 – AakashM

+0

我知道,但這種情況會重複,所以我問。 –

回答

2

第1步:使用您的ORM加載記錄(例如,linqToSql)。使用正確的設置,記錄之間的所有關係都會自動生成。

第2步:使用正常碼周遊內存樹:

public static IEnumerable<T> WalkTreeBreadthFirst<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> childFunction) 
    { 
     // http://en.wikipedia.org/wiki/Breadth-first_search 
     HashSet<T> seenIt = new HashSet<T>(); 
     Queue<T> toVisit = new Queue<T>(); 

     foreach (T item in source) 
     { 
      toVisit.Enqueue(item); 
     } 

     while (toVisit.Any()) 
     { 
      T item = toVisit.Dequeue(); 
      if (!seenIt.Contains(item)) 
      { 
       seenIt.Add(item); 
       foreach (T child in childFunction(item)) 
       { 
        toVisit.Enqueue(child); 
       } 
       yield return item; 
      } 
     } 
    } 

    public static IEnumerable<T> WalkTreeDepthFirst<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> childFunction) 
    { 
     // http://en.wikipedia.org/wiki/Depth-first_search 
     HashSet<T> seenIt = new HashSet<T>(); 
     Stack<T> toVisit = new Stack<T>(); 

     foreach (T item in source.Reverse()) 
     { 
      toVisit.Push(item); 
     } 

     while (toVisit.Any()) 
     { 
      T item = toVisit.Pop(); 
      if (!seenIt.Contains(item)) 
      { 
       seenIt.Add(item); 
       foreach (T child in childFunction(item).Reverse()) 
       { 
        toVisit.Push(child); 
       } 
       yield return item; 
      } 
     } 
    } 

例如:

List<Person> bosses = tree.GetBossesByID(3, 4, 5); 
List<Shovel> shovels = bosses 
    .WalkTreeBreadthFirst(x => x.Subordinates) 
    .Select(p => p.Shovel) 
    .ToList(); 
+0

我想我還是不明白這個概念,或許是一個更清晰的例子? –