2010-06-23 2 views
1

Если у меня есть набор данных сотрудников, подобные:Иерархического наслоение в 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"} 
}; 

Можно ли использовать Linq для добавления иерархических слоев, в том смысле, что:

  • CEO = 1 (верхний)
  • CIO = 2 (уровень 2)
  • XDIR и YDIR = 3 (третий уровень)
  • АМНГР = 4 (и т.д.)
  • АСУП = 5 (и т.д.)

Я был в состоянии сгруппировать сотрудников согласно SupervisorID, но не знаете, как сделать «уровень» произойдет.

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

Большое спасибо.

+0

Вы хотите, чтобы уровень был уровнем, применяемым ко всем членам группы. Если вы посмотрите на генерального директора группы, то есть 2 уровня с этим. –

+0

@ Leom, CEO supervisorid является избыточным, CEO supervisor = CEO.Поэтому идея заключается в том, что там, где SupervisorId = UserId, вы генеральный директор - дерево начинается там. – dizzyguy

ответ

0

Я хотел бы добавить рейтинг к вашему Linq «объект пользователя»

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 

    } 

    } 
} 

Тогда ваш Linq вы бы добавить присоединиться.

 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

Update

Heres один способ создать таблицу поиска для каждого уровня. Это справедливо, и я не знаю, как это будет масштабироваться. Очевидно, вам нужно будет адаптировать его, чтобы вытащить строки из вашей базы данных.

Определить класс для хранения нашей таблицы перекодировки

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

Тогда мы получим уникальный список комбинаций UserId/SupervisorID и перебрать список расчета уровня для каждой комбинации по «Пешеходному» вверх по дереву.

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

Теперь вы можете использовать uniqueusers в качестве таблицы поиска, чтобы определить уровень для вашего запроса. например

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

Возможно, вы могли бы даже объединить это в один шаг с небольшим усилием.

+0

Такая же проблема, как указано выше ... результаты на самом деле получены из базы данных, и я не могу жестко кодировать любые слои. Код должен быть способен вывести уровень, основанный на идее, что: 1) Генеральный директор - это главный узел, где supervisorID - userID и 2) каждый слой под ним определяется, например, supervisorID, если ваш руководитель CEO, тогда вы - уровень 2 и т. Д. ... – dizzyguy

+0

Позвольте мне исправить это второе утверждение, если ваш руководитель - генеральный директор, а ваш пользователь - генеральный директор, тогда вы являетесь генеральным директором. но он работает на каждом уровне ниже, как указано выше. – dizzyguy

+0

Это выглядит ОЧЕНЬ многообещающим! Сегодня я попробую. Спасибо! – 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"); 

Отказ от ответственности:

  • не обрабатывает несколько руководителей.
  • Сохраняет круговые отношения.
  • Листья сироты позади.
+0

В настоящее время у меня нет определенного типа пользователя. Можете ли вы объяснить, как я буду реализовывать это? – dizzyguy

+0

Я собираюсь попытаться реализовать пользователя как новый класс с определенными выше свойствами и посмотреть, работает ли это. – dizzyguy

0

Это вы что искали?

  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

Проблема в том, что я извлекаю эти значения из базы данных. Код для пользователей объектов - всего лишь пример. Моя база данных содержит только идентификатор пользователя и идентификатор супервизора, и мне нужно иметь возможность INFIR-иерархии, используя это в качестве основного. – dizzyguy

Смежные вопросы