Какие таблицы и связи нужны для хранения иерархии сотрудников с руководителями и подчиненными
Что проверяют
Умеете ли вы хранить дерево в реляционной базе и понимаете ли, чем платите за каждый способ. Следом обычно спрашивают, как одним запросом получить всех подчинённых на любую глубину и как это выразить в EF Core.
Как отвечать
Базовый вариант, список смежности: одна таблица Employees с Id и nullable ManagerId, внешний ключ на ту же таблицу. У генерального директора ManagerId пустой. Индекс на ManagerId обязателен, иначе поиск подчинённых сканирует таблицу. Отделы выносятся в Departments.
В EF Core это самоссылка: HasOne(e => e.Manager).WithMany(e => e.Subordinates).HasForeignKey(e => e.ManagerId) с OnDelete(DeleteBehavior.Restrict). Restrict здесь не формальность: SQL Server не даст создать каскадное удаление на самоссылке из-за возможных циклов.
Всё поддерево достаётся рекурсивным CTE (WITH ... UNION ALL). LINQ такое не строит, поэтому запрос пишут через FromSql или прячут в представление. В SQL Server глубина рекурсии по умолчанию ограничена 100 уровнями (MAXRECURSION).
Затем назовите альтернативы под другие нагрузки:
- closure table: отдельная таблица
(AncestorId, DescendantId, Depth)со всеми парами предок-потомок. Поддерево читается простымJOIN, но перенос ветки переписывает много строк; - materialized path: строка вида
/1/7/42/, поддерево ищется по префиксу. В PostgreSQL для этого есть типltree; hierarchyidв SQL Server: встроенный тип с методамиGetAncestorиIsDescendantOf, EF Core поддерживает его начиная с восьмой версии;- несколько руководителей (матричная структура): связующая таблица
EmployeeManagers(EmployeeId, ManagerId, Role).
Где спотыкаются
Не защищаются от циклов. База сама не запретит сотруднику стать руководителем своего начальника, и рекурсивный запрос будет крутиться до лимита.
Загружают дерево через ленивые навигации и получают отдельный запрос на каждый узел.
Не спрашивают про историю. Если нужно знать, кто был руководителем полгода назад, одного ManagerId мало, нужна таблица назначений с датами начала и конца.