2012-11-08 7 views
1

Imaginez une situation où vous avez une table avec des utilisateurs, dans laquelle nos utilisateurs ont une structure hiérarchique.Données hiérarchiques & LINQ - meilleures pratiques

[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; } 

Placez les exemples de données là-bas:

UserId UserParentId UserName

  • 1 | null | Boss
  • 2 | 1 | Gestionnaire Diana
  • 3 | 2 | Travailleur Sam
  • 4 | 2 | Travailleur Bob
  • 5 | 1 | Gestionnaire Wong
  • 6 | 5 | Travailleur Lu

attribuer à chaque utilisateur une pelle: P

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

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

Placer l'échantillon des données là-bas:

ShovelId ShovelSerialNumbe UserId

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

Le but de tout cela est d'obtenir le numéro de série des pelles, avec une requête hiérarchique sur la table des utilisateurs. Le patron verra toutes les pelles, mais seulement les pelles Gère les employés subalternes.

Toutes les idées et conseils sur la façon d'y parvenir dans LINQ, en tenant compte du fait qu'il peut y avoir plusieurs milliers d'employés et plusieurs milliers de pelles, et ne connaissent pas la profondeur de la hiérarchie de la dépression.

Thx pour l'aide.

+0

Vous avez utilisé des balises ORM, ce qui suggère qu'il ya une base de données en cause, auquel cas tous les trucs hiérarchiques devraient être faits dans la base de données. LINQ ne peut pas vraiment exprimer une requête hiérarchique. – AakashM

+0

Je sais, mais ce genre de situation sera répétée, donc je demande. –

Répondre

2

Etape 1: chargez les enregistrements à l'aide de votre ORM (par exemple, linqToSql). Avec les bons paramètres, toutes les relations entre les enregistrements seront automatiquement mises en place.

Etape 2: utiliser le code normal de voyager autour de l'arbre en mémoire:

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

Par exemple:

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

Je pense que je ne comprends toujours pas le concept, peut-être un exemple plus clair? –