linq to sql递归查询

时间:2010-11-01 19:00:26

标签: c# linq linq-to-sql

EmployeeId  Name  ManagerId
------------------------------
1           A     null
2           B     null
3           C     1
4           D     3
5           E     2

只需使用此表,如何编写linq查询(使用linq to sql)以递归方式获取父数据。

例如,如果选择的雇主ID为4,则应该给出ID为4,3,1的员工列表

感谢。

4 个答案:

答案 0 :(得分:7)

这个.AsHierarchy()扩展方法可能很有用:link。但是,这只能通过提供一种将结果抛出到链接对象的简单方法来实现。为了做到这一点,它只会获取所有记录并运行自己的本地递归查询。

如果您正在寻找将通过LINQ to SQL直接转换为递归SQL查询的LINQ查询,您将无法找到它。为了获得最佳性能,存储过程中的CTE可能就是您正在寻找的。如果你有一个非常简单的页面需要加载整个树,AsHierarchy方法可能会满足你的需求。

答案 1 :(得分:2)

我不确定这是否正是你想要的,但是这里有一个使用一些linq的递归方法,确保不要进入无限循环:

    public static IEnumerable<Employee> GetTreeForEmployeeNumber(this IEnumerable<Employee> source, int startingId) {
        var result = source.Where(x => x.EmployeeId == startingId).FirstOrDefault();
        if (result != null) {
            var resultAsE = new [] { result };
            if (!result.ManagerId.HasValue)
                return resultAsE;
            return resultAsE.Union(source.Except(resultAsE).GetTreeForEmployeeNumber(result.ManagerId.Value));
        }
        return new Employee [] { };
    }

如果您安装了linqpad,则可以使用以下脚本对其进行测试:

void Main()
{
    var lst = new [] {
        new Extensions.Employee{ EmployeeId = 1, Name = "A", ManagerId = null }, 
        new Extensions.Employee{ EmployeeId = 2, Name = "B", ManagerId = null }, 
        new Extensions.Employee{ EmployeeId = 3, Name = "C", ManagerId = 1 }, 
        new Extensions.Employee{ EmployeeId = 4, Name = "D", ManagerId = 3 }, 
        new Extensions.Employee{ EmployeeId = 5, Name = "E", ManagerId = 2 }
    };

    lst.GetTreeForEmployeeNumber(4).Dump();
}

public static class Extensions {

    public class Employee {
        public int EmployeeId { get; set; }
        public string Name { get; set; }
        public int? ManagerId { get; set; }
    }

    public static IEnumerable<Employee> GetTreeForEmployeeNumber(this IEnumerable<Employee> source, int startingId) {
        var result = source.Where(x => x.EmployeeId == startingId).FirstOrDefault();
        if (result != null) {
            var resultAsE = new [] { result };
            if (!result.ManagerId.HasValue)
                return resultAsE;
            return resultAsE.Union(source.Except(resultAsE).GetTreeForEmployeeNumber(result.ManagerId.Value));
        }
        return new Employee [] { };
    }
}

答案 2 :(得分:0)

var managedEmployees = ctx.Employess.Where(x => x.ManagerId = 4).AsEnumerable()

如果您想同时使用整棵树,解决方案会更复杂。在SQL中,最好用CTE完成,我不知道EF是否可以使用linq来处理这个问题 - 更可能使用迭代解决方案。

答案 3 :(得分:0)

您可以执行类似

的操作
    int id = 5;
    do
    {
        employee= employeedata.FirstOrDefault(e => e.EmployeeId == id);

    } while (employee != null && (id = employee.ManagerId) != 0);

但这是一件相当危险的事情,因为它可能陷入无限循环。据我所知,除非你编写存储过程,否则无法直接进行递归查询。