2010-11-01 22 views
15
EmployeeId Name ManagerId 
------------------------------ 
1   A  null 
2   B  null 
3   C  1 
4   D  3 
5   E  2 

simplemente usando esta tabla, ¿cómo se puede escribir una consulta linq (usando linq a sql) para obtener los datos padre recursivamente?consulta recursiva de linq a sql

Por ejemplo, si el Número de Identificación seleccionado es 4 debe dar lista de los empleados con Id: 4, 3, 1

Gracias.

+0

4,3,1 ?? ¿Qué tipo de algoritmo estás diciendo? :) ¿Qué sucederá si selecciono 5? –

+0

@Serkan: Eso debería dar una lista de empleado (s) con id: 5, 2 – stackoverflowuser

+0

Todavía no puedo entenderte. 2 es managerId? Si es así, según entiendo. ¿Desea seleccionar EmployeeId y el EmployeeId's managerId como EmployeeId? –

Respuesta

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

Si quieres todo el árbol a la vez, la solución es más compleja. En SQL es mejor hacerlo con un CTE, no sé si EF puede manejar esto usando linq, es más probable que se use una solución iterativa.

0

Se podría hacer algo como

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

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

pero es una cosa bastante peligroso hacerlo, ya que pueden quedar atrapados en un bucle infinito. Por lo que sé, no hay forma de hacer una consulta recursiva directamente a menos que escriba un procedimiento almacenado.

+0

Sí, sé que se puede hacer escribiendo CTE dentro de un proceso almacenado. Quería ver si hay una manera de lograr eso directamente a través de la expresión linq a sql. Parece que las respuestas se están orientando hacia "NO". – stackoverflowuser

+0

hmm :) No escuché una expresión que pueda hacer recursivo. Pensé que estabas preguntando cómo hacer programáticamente :) –

7

Este método de extensión .AsHierarchy() puede ser útil: link. Sin embargo, esto solo funciona al proporcionar una manera fácil de arrojar los resultados en objetos vinculados. Para hacer eso, obtendrá todos los registros y ejecutará su propia consulta recursiva local.

Si está buscando una consulta LINQ que se traduzca directamente en una consulta SQL recursiva a través de LINQ a SQL, no la encontrará. Para obtener el mejor rendimiento, es probable que un CTE en un procedimiento almacenado sea lo que está buscando. Si tiene una página realmente simple que necesita cargar todo el árbol de todos modos, el método AsHierarchy probablemente se ajuste a sus necesidades.

2

No estoy seguro si esto es exactamente lo que quiere, sino aquí es un método iterativo que usa algún LINQ que se asegura de no entrar en un bucle infinito

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

Si ha instalado linqpad se puede probar esto con la siguiente secuencia de comandos:

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