Linq to Sql - Иерархический запрос для поиска предков - PullRequest
4 голосов
/ 25 октября 2008

Учитывая EmployeeId, как я могу создать запрос Linq to Sql, чтобы найти всех предков сотрудника? Каждый EmployeeId имеет связанный SupervisorId (см. Ниже).

Например, запрос предков для EmployeeId 6 (Фрэнк Блэк) должен вернуть Джейн Доу, Боба Смита, Джо Блоггса и Хончо Хед.

При необходимости я могу кэшировать список всех сотрудников для повышения производительности.

UPDATE:

Я создал следующий грубый метод для выполнения задачи. Он пересекает отношения employee.Supervisor вплоть до корневого узла. Однако это вызовет один вызов базы данных для каждого сотрудника. У кого-нибудь есть более сжатый или более эффективный метод? Спасибо.

private List<Employee> GetAncestors(int EmployeeId)
{
    List<Employee> emps = new List<Employee>();
    using (L2STestDataContext dc = new L2STestDataContext())
    {
        Employee emp = dc.Employees.FirstOrDefault(p => p.EmployeeId == EmployeeId);
        if (emp != null)
        {
            while (emp.Supervisor != null)
            {
                emps.Add(emp.Supervisor);
                emp = emp.Supervisor;
            }
        }
    }
    return emps;
}

Ответы [ 2 ]

1 голос
/ 27 октября 2008

Простое решение, которое позволяет избежать загрузки всей таблицы Employee (но имеет ограниченную глубину обхода): ...

var emps = dc.Employees.Where(e => (e.EmployeeId == EmployeeId) ||
                                   (e.SupervisorId == EmployeeId) ||
                                   (e.Supervisor.SupervisorId == EmployeeId) ||
                                   (e.Supervisor.Supervisor.SupervisorId == EmployeeId) ||
                                   ...);

В конечном счете, вы должны использовать общее табличное выражение , чтобы выровнять иерархию, но LINQ to SQL в настоящее время не поддерживает это. Вы можете написать свой собственный метод расширения (например, тот, что в библиотеке Омера, но использующий IQueryable вместо IEnumerable для поддержки выполнения на стороне сервера).

1 голос
/ 26 октября 2008

Прежде всего, вы можете использовать иерархические запросы в моем проекте LINQ Extension Methods . Я думаю, что может помочь упростить ваш код.

Проблема здесь в том, что это создаст вызов базы данных для каждого узла в иерархии. В случае вашего примера у вас будет 5 поездок в базу данных.

Я бы пошел другим путем и создал бы хранимую процедуру, чтобы сделать это для меня и вернуть весь набор Employee объектов. Поскольку вы отключаете объекты перед их возвратом (избавляясь от контекста), вы можете просто создать новый объект из набора результатов хранимой процедуры.

...