2010-06-23 2 views
1

Si j'ai un ensemble de données d'employés similaires à:stratification hiérarchique dans LINQ

var users = new[] 
{ 
    new {SupervisorId = "CEO", UserId = "CEO", UserName = "Joe"}, 
    new {SupervisorId = "CEO", UserId = "CIO", UserName = "Mary"}, 
    new {SupervisorId = "CIO", UserId = "XDIR", UserName = "Ed"}, 
    new {SupervisorId = "CIO", UserId = "YDIR", UserName = "Lisa"}, 
    new {SupervisorId = "XDIR", UserId = "AMNGR", UserName = "Steve"}, 
    new {SupervisorId = "AMNGR", UserId = "ASUP", UserName = "Lesley"} 
}; 

Serait-il possible d'utiliser LINQ pour ajouter des couches hiérarchiques, dans le sens où:

  • PDG = 1 (en haut)
  • CIO = 2 (deuxième niveau)
  • XDIR et Ydir = 3 (troisième niveau)
  • AMNGR = 4 (etc)
  • ASUP = 5 (etc.)

Je suis en mesure de regrouper les employés selon SupervisorId, mais pas sûr de savoir comment faire le « niveau » se produire.

var userGroups = from user in users 
    group user by user.SupervisorId into userGroup 
    select new 
    { 
    SupervisorId = userGroup.Key, 
    Level = ?????? 
    Users = userGroup.ToList() 
    }; 

    foreach (var group in userGroups) 
    { 
    Console.WriteLine("{0} - {1} - {2}", group.SupervisorId, group.Level, group.Users.Count); 
    } 

Merci beaucoup.

+0

Voulez-vous que le niveau soit le niveau appliqué à tous les membres du groupe. Si vous regardez le PDG du groupe, il y a 2 niveaux avec ça. –

+0

@Leom, le PDG supervisorid est redondant, superviseur PDG = PDG.Donc l'idée est que là où SupervisorId = UserId, vous êtes CEO - l'arbre commence là. – dizzyguy

Répondre

0

J'ajouterais un classement à votre LINQ « objet utilisateur »

public class User{ 

    public string SupervisorId {get;set;} 
    public string UserId {get;set;} 
    public string UserName {get;set;} 
    public int Level {get { return GetRank(SupervisorId ) ; } } 

    private int GetRank(string userId){ 
    if(string.IsNullOrEmpty(userId)){ 
     //Bad case, probably want to use a very large number 
     return -1; 
    } 
    int level = 0; 
    switch(userId){ 
     case "CEO": 
      level = 0; 
      break; 

     //insert others here 

    } 

    } 
} 

Ensuite, votre Linq vous ajouteriez une jointure.

 var userGroups = from user in users 
        join super in users on user.SupervisorId equals super.UserId 
        group user by user.SupervisorId into userGroup 
        select new 
    { 
     SupervisorId = userGroup.Key, 
     Level = super.Level, 
     Users = userGroup.ToList() 
    }; 
0

Mise à jour

Heres une façon de créer une table de consultation pour chaque niveau. C'est juste et je ne sais pas comment cela va évoluer. Évidemment, vous devrez l'adapter pour extraire les lignes de votre base de données.

Définir une classe pour tenir notre table de recherche

public class user{ 
    public string SupervisorId; 
    public string UserId; 
    public int Level; 
} 

Ensuite, nous obtenons une liste unique de combinaisons UserId/SupervisorId et boucle dans la liste calcul du niveau pour chaque combinaison par « la marche » l'arbre.

var uniqueusers = (new user[] 
     { 
      new user {SupervisorId = "CEO", UserId = "CEO"}, 
      new user {SupervisorId = "CEO", UserId = "CIO"}, 
      new user {SupervisorId = "CIO", UserId = "XDIR"}, 
      new user {SupervisorId = "CIO", UserId = "YDIR"}, 
      new user {SupervisorId = "XDIR", UserId = "AMNGR"}, 
      new user {SupervisorId = "AMNGR", UserId = "ASUP"} 
     }).Distinct(); 


     foreach (var item in uniqueusers) 
     {   
      int level = 0; 
      user CurrentUser = item; 
      while (CurrentUser.UserId != CurrentUser.SupervisorId){ 
       CurrentUser = uniqueusers.Where(c => c.UserId == CurrentUser.SupervisorId).FirstOrDefault(); 
       level++; 
      } 
      item.Level = level;    
     } 

Maintenant, vous pouvez utiliser les uniqueusers comme table de recherche pour déterminer le niveau de votre requête. par exemple

private int GetLevel(string userId){   
    return uniqueusers.Where(c => c.UserId == userId).FirstOrDefault().Level;  
    } 

Vous pourriez probablement même combiner ceci en une seule étape avec un peu d'effort.

+0

Même problème que mentionné ci-dessus ... les résultats proviennent en fait d'une base de données et je ne peux pas coder en dur toute sorte de superposition. Le code doit pouvoir déduire le niveau basé sur l'idée que: 1) le CEO est le nœud supérieur, où supervorID - userID, et 2) chaque couche en dessous est définie par supervorID, ex., Si votre superviseur est Chef de la direction, alors vous êtes le niveau 2, et ainsi de suite ... – dizzyguy

+0

Permettez-moi de corriger cette deuxième déclaration, si votre superviseur est PDG et votre ID utilisateur est PDG, alors vous êtes PDG. mais cela fonctionne pour chaque niveau en dessous comme indiqué ci-dessus. – dizzyguy

+0

Cela semble très prometteur! Je vais essayer aujourd'hui. Je vous remercie! – dizzyguy

0
ILookup<string, User> subordLookup = users 
    .ToLookup(u => u.SupervisorId); 

foreach(User user in users) 
{ 
    user.Subordinates = subordLookup[user.UserId].ToList(); 
} 

User userHierarchy = user.Single(u => u.UserId == "CEO"); 

Avertissements:

  • ne gère pas les PDG multiples.
  • Préserve relations circulaires.
  • Feuilles orphelins derrière.
+0

Je n'ai pas défini de type d'utilisateur pour le moment. Pouvez-vous m'expliquer comment je pourrais mettre en œuvre cela? – dizzyguy

+0

Je vais essayer d'implémenter User en tant que nouvelle classe avec les fonctionnalités définies ci-dessus et voir si cela fonctionne. – dizzyguy

0

Est-ce que vous cherchez?

  var levels = new[] 
     { 
      new { Level = 1, LevelName = "CEO" }, 
      new { Level = 2, LevelName = "CIO" }, 
      new { Level = 3, LevelName = "XDIR" }, 
      new { Level = 3, LevelName = "YDIR" }, 
      new { Level = 4, LevelName = "AMNGR" }, 
      new { Level = 5, LevelName = "ASUP" } 
     };       

     var userGroups = from user in users 
         join level in levels on 
         user.UserId equals level.LevelName        
         group new{ User = user, Level = level.Level } by new { SuperId = user.SupervisorId, Level = level.Level } into userGroup 
         select new 
          { 
           SupervisorId = userGroup.Key.SuperId, 
           Level = userGroup.Key.Level, 
           Users = userGroup.ToList() 
          }; 
+0

Le problème est que je récupère ces valeurs à partir d'une base de données. Le code pour les utilisateurs d'objets est juste un exemple. Ma base de données contient uniquement l'ID de l'utilisateur et l'ID du superviseur, et je dois être en mesure d'INFER la hiérarchie à partir de cela - en utilisant le PDG comme racine. – dizzyguy

Questions connexes