Рекурсивный запрос 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) для рекурсивного извлечения родительских данных.
Например, если выбран идентификатор работодателя 4, он должен предоставить список сотрудников с идентификаторами: 4, 3, 1
Спасибо.
Ответы
Ответ 1
Этот метод расширения .AsHierarchy() может оказаться полезным: ссылка. Тем не менее, это только работает, предоставляя простой способ передать результаты в связанные объекты. Чтобы сделать это, он просто получит все записи и запустит свой локальный рекурсивный запрос.
Если вы ищете запрос LINQ, который будет напрямую переводить на рекурсивный SQL-запрос через LINQ to SQL, вы его не найдете. Для лучшей производительности CTE в хранимой процедуре, вероятно, вы ищете. Если у вас действительно простая страница, которая все равно должна загружать все дерево, метод AsHierarchy, вероятно, будет соответствовать вашим потребностям.
Ответ 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, вы можете протестировать его со следующим 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 [] { };
}
}
Ответ 3
var managedEmployees = ctx.Employess.Where(x => x.ManagerId = 4).AsEnumerable()
Если вам нужно сразу все дерево, решение будет более сложным. В SQL лучше всего это делается с помощью CTE, я не знаю, может ли EF справиться с этим с помощью linq - скорее, будет использоваться итерационное решение.
Ответ 4
Вы можете сделать что-то вроде
int id = 5;
do
{
employee= employeedata.FirstOrDefault(e => e.EmployeeId == id);
} while (employee != null && (id = employee.ManagerId) != 0);
но это довольно опасная вещь, поскольку она может застрять в бесконечном цикле. Насколько я знаю, нет никакого способа сделать рекурсивный запрос напрямую, если вы не напишите хранимую процедуру.