首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >基于LINQ的HIerarchical数据表示

基于LINQ的HIerarchical数据表示
EN

Stack Overflow用户
提问于 2014-05-11 14:17:03
回答 1查看 796关注 0票数 2

所有这些,我都试图使用LINQ.Can与下面类的分层数据表示形式相结合-请帮助我

代码语言:javascript
复制
public class Employee
    {
       public Employee(int empId,int? managerId)
       {
           this.Id = empId;
           this.MangerId = managerId;
           this.Children = new List<Employee>();
       }
        public int Id { get; set; }
        public int? MangerId { get; set; }
        public string EmployeeName { get; set; }
        public List<Employee> Children { get; set; }
    }

样本数据

代码语言:javascript
复制
var empList = new List<Employee>
             {
                 new Employee(1,2){EmployeeName = "Joseph"},
                 new Employee(2,3){EmployeeName = "Smith"},                 
                 new Employee(3,4){EmployeeName = "Bob"},
                 new Employee(4,null){EmployeeName = "Doug"},
                 new Employee(5,2){EmployeeName = "Dave"},
                 new Employee(6,4){EmployeeName = "Allan"}
             };

输出应该是这样的

/*道格鲍勃艾伦史密斯约瑟夫戴夫

*/

任何帮助都将不胜感激。

编辑:顶级员工的managerId将为null

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-05-11 16:00:47

使用您的模型,员工模型不会直接链接到自己。相反,我们必须使用它们的标识符来遍历层次结构。

首先,我们得到根雇员:

代码语言:javascript
复制
var rootEmp = EmpList.Single(e => e.MangerId == null);

然后,我们使用递归函数遍历层次结构:

代码语言:javascript
复制
string WalkEmployees(Employee root)
{
    // Create the container of the names
    var builder = new StringBuilder();

    // Get the children of this employee
    var children = EmpList.Where(e => e.MangerId == root.Id);

    // Add the name of the current employee in the container
    builder.Append(root.EmployeeName + " ");

    // For each children, walk them recursively
    foreach (var employee in children)
    {
        builder.Append(WalkEmployees(employee));
    }

    // Return the container of names
    return builder.ToString();
}

最后,我们调用该函数:

代码语言:javascript
复制
WalkEmployees(rootEmp);

从本质上讲,递归函数垂直地遍历层次结构:

道格

  • 鲍勃
    • 史密斯

    • 约瑟夫

    • 戴夫

  • 艾伦

尽管如此,您希望水平行走,以使艾伦在鲍勃的权利。为此,我为您的员工添加了一个视图模型,该模型描述了他们在层次结构中的级别。

代码语言:javascript
复制
public class EmployeeViewModel
{
    public EmployeeViewModel(Employee employee, int level)
    {
        Employee = employee;
        Level = level;
    }

    public Employee Employee { get; set; }
    public int Level { get; set; }
}

员工走路的功能变成:

代码语言:javascript
复制
IEnumerable<EmployeeViewModel> WalkEmployees(Employee root, int level)
{
    // Create the container of the employees
    var container = new List<EmployeeViewModel> {new EmployeeViewModel(root, level)};

    // Get the children of this employee
    var children = EmpList.Where(e => e.MangerId == root.Id);

    // For each children, walk them recursively
    foreach (var employee in children)
    {
        container.AddRange(WalkEmployees(employee, level + 1));
    }

    // Return the container
    return container;
}

并呼吁:

代码语言:javascript
复制
var rootEmp = EmpList.Single(e => e.MangerId == null);

var employees = WalkEmployees(rootEmp, 0);

// Order the employees by its level in the hierarchy
var orderedEmployees = employees.OrderBy(vm => vm.Level);

// Display the names
foreach (var orderedEmployee in orderedEmployees)
{
    Console.Write(orderedEmployee.Employee.EmployeeName + " ");
}

你得到的结果是:

道格

  • 鲍勃
  • 艾伦
    • 史密斯

    • 约瑟夫

    • 戴夫

奖金

由于模型之间缺乏联系,您的模型很难处理。以下是一个更有力的建议:

代码语言:javascript
复制
public class Employee
{
    #region Constructors
    public Employee()
    {
        Employees = new List<Employee>();
    }

    public Employee(string name) : this()
    {
        Name = name;
    }

    public Employee(string name, Employee manager) : this(name)
    {
        Manager = manager;
    }

    public Employee(string name, Employee manager, params Employee[] employees) : this(name, manager)
    {
        Employees.AddRange(employees);
    }
    #endregion

    #region Properties
    public List<Employee> Employees { get; set; }
    public int Id { get; set; }
    public Employee Manager { get; set; }
    public string Name { get; set; }
    #endregion
}

您现在可以这样生成您的员工了:

代码语言:javascript
复制
/// <summary>
/// Generates the employees in a hierarchy way.
/// </summary>
/// <returns>Returns the root employee.</returns>
Employee GenerateEmployees()
{
    var doug = new Employee("Doug");
    doug.Employees.Add(new Employee("Allan", doug));

    var bob = new Employee("Bob", doug);
    doug.Employees.Add(bob);

    var smith = new Employee("Smith", bob);
    bob.Employees.Add(smith);

    smith.Employees.Add(new Employee("Joseph", smith));
    smith.Employees.Add(new Employee("Dave", smith));

    return doug;
}

你的行走功能变成:

代码语言:javascript
复制
string WalkEmployees(Employee root)
{
    var builder = new StringBuilder();

    builder.Append(root.Name + " ");

    foreach (var employee in root.Employees)
    {
        builder.Append(WalkEmployees(employee));
    }

    return builder.ToString();
}

如果使用EntityFramework使用导航属性设计数据库,则此实现更有意义。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/23593687

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档