简体   繁体   English

使用LINQ的分层数据表示

[英]HIerarchical Data representation using LINQ

All,I was trying to comeup with a hierarchical data representation of the following class using LINQ.Can anyone please help me out 所有,我试图使用LINQ提出以下类的分层数据表示。有人可以帮帮我吗

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

Sample Data 样本数据

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

and the output should be like this 输出应该是这样的

/* Doug Bob Allan Smith Joseph Dave / *道格·鲍勃·艾伦·史密斯·约瑟夫·戴夫

*/ * /

Any help would be greatly appreciated 任何帮助将不胜感激

edit: The top employee will have a managerId of null 编辑:最高员工的经理编号为null

Using your model, the Employee models are not directly linked to themselves. 使用您的模型,Employee模型不会直接链接到它们自己。 Instead, we must use their identifier to walk the hierarchy. 相反,我们必须使用它们的标识符来遍历层次结构。

First, we get the root employee: 首先,我们获得根员工:

var rootEmp = EmpList.Single(e => e.MangerId == null);

Then, we walk the hierarchy using a recursive function: 然后,我们使用递归函数遍历层次结构:

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

Finally, we call the function: 最后,我们调用函数:

WalkEmployees(rootEmp);

By essence, recursive functions walk the hierarchy vertically: 本质上,递归函数垂直遍历层次结构:

Doug 道格
- Bob 鲍勃
- - Smith --史密斯
- - Joseph - - 约瑟夫
- - Dave --戴夫
- Allan -艾伦

Nonetheless, you expect an horizontal walk in order to get Allan right after Bob. 但是,您希望水平行走才能使Allan紧随Bob。 For that purpose, I added a view model for your employees, that describes their level in the hierarchy. 为此,我为您的员工添加了一个视图模型,该视图模型描述了他们在层次结构中的级别。

public class EmployeeViewModel
{
    public EmployeeViewModel(Employee employee, int level)
    {
        Employee = employee;
        Level = level;
    }

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

The function to walk the employees becomes: 行走员工的功能变为:

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

and its call: 及其调用:

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

you get this result: 您得到以下结果:

Doug 道格
- Bob 鲍勃
- Allan -艾伦
- - Smith --史密斯
- - Joseph - - 约瑟夫
- - Dave --戴夫

Bonus 奖金

your model is quite hard to handle, due to the lack of link between the models. 由于模型之间缺乏链接,因此您的模型很难处理。 Here is a suggestion for a stronger one: 这是一个更强大的建议:

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
}

You can now generate your employees like that: 您现在可以像这样生成您的员工:

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

And your walk function becomes: 您的步行功能变为:

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

This implementation makes more sense if you use EntityFramework to design a database using the navigation properties. 如果您使用EntityFramework通过导航属性设计数据库,则此实现更有意义。

Try: 尝试:

string text = string.Join(" ",
    from i in empList
    orderby i.MangerId.HasValue, i.MangerId descending
    select i.EmployeeName);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM