Как хранить непосредственного руководителя в таблице работников
Что проверяют
Знаете ли вы самоссылающуюся связь и умеете ли с ней жить: корень иерархии, удаление руководителя, выборка всей ветки подчинённых. Для C#-разработчика следом спрашивают, как описать это в EF Core и как достать всех подчинённых на любой глубине.
Как отвечать
Руководитель это одна колонка в той же таблице: ManagerId, внешний ключ на Employees(Id), допускает NULL. У директора руководителя нет, он и есть корень.
В EF Core:
- сущность:
int? ManagerId, навигацияEmployee? Managerи коллекцияICollection<Employee> Subordinates; - конфигурация:
HasOne(e => e.Manager).WithMany(e => e.Subordinates).HasForeignKey(e => e.ManagerId); - удаление:
OnDelete(DeleteBehavior.Restrict)илиNoAction. Каскад на самоссылке SQL Server не примет, он ругается на циклы и множественные пути каскада, да и по смыслу увольнение руководителя не должно удалять отдел; - проверка:
CHECK (ManagerId <> Id)запрещает быть начальником самому себе. Длинные циклы (A подчиняется B, B подчиняется A) ограничение не ловит, их проверяют в коде при смене руководителя.
Всех подчинённых на любой глубине достаёт рекурсивный CTE: WITH в SQL Server или WITH RECURSIVE в PostgreSQL. LINQ такое не переводит, поэтому запрос пишут через FromSql или выносят в представление. Для небольшой компании нормально загрузить всю таблицу и собрать дерево в памяти.
Если деревья читаются часто, назовите альтернативы: тип hierarchyid в SQL Server (EF Core поддерживает его начиная с восьмой версии), материализованный путь, таблица замыканий. Если у сотрудника бывает несколько руководителей (матричная структура) или нужна история смен, одной колонки мало: нужна отдельная таблица со сроками действия.
Где спотыкаются
Хранят имя руководителя строкой. Переименование или однофамилец ломают связь, ссылочной целостности нет.
Достают подчинённых ленивой загрузкой Subordinates рекурсивно в цикле. Каждый сотрудник превращается в отдельный запрос, и на дереве из тысячи человек это тысяча обращений к базе.
Не решают, что делать с подчинёнными при удалении руководителя. Ответ «переназначаем их на вышестоящего в той же транзакции» звучит лучше молчания.