linq to sql recursive query

后端 未结 4 449
感情败类
感情败类 2020-12-06 05:12
EmployeeId  Name  ManagerId
------------------------------
1           A     null
2           B     null
3           C     1
4           D     3
5           E     2
         


        
相关标签:
4条回答
  • 2020-12-06 05:35

    I'm not sure if this is exactly what you want, but here is one recursive method that uses some linq that makes sure not to enter an infinite loop:

        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 [] { };
        }
    

    If you have linqpad installed you can test this with the following script:

    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 [] { };
        }
    }
    
    0 讨论(0)
  • 2020-12-06 05:51

    You could do something like

        int id = 5;
        do
        {
            employee= employeedata.FirstOrDefault(e => e.EmployeeId == id);
    
        } while (employee != null && (id = employee.ManagerId) != 0);
    

    but it's a rather dangerous thing to do since it can get stuck in an infinite loop. As far as I know there's no way to make a recursive query directly unless you write a stored procedure.

    0 讨论(0)
  • 2020-12-06 05:52

    This .AsHierarchy() extension method may be useful: link. However, this only works by providing an easy way to throw your results into linked objects. In order to do that, it'll just get all the records and run its own local recursive query.

    If you're looking for a LINQ query that will directly translate to a recursive SQL query via LINQ to SQL, you won't find it. For the best performance, a CTE in a stored procedure is probably what you're looking for. If you have a really simple page that needs to load the whole tree anyway, the AsHierarchy method would probably fit your needs.

    0 讨论(0)
  • 2020-12-06 05:52
    var managedEmployees = ctx.Employess.Where(x => x.ManagerId = 4).AsEnumerable()
    

    If you want the whole tree at once, the solution is more complex. In SQL its best done with an CTE, I don't know if EF can handle this using linq- more likely an iterative solution would be used.

    0 讨论(0)
提交回复
热议问题