Какие типы данных для древовидных структур поддерживаются в PostgreSQL
Что проверяют
Знаете ли вы, что отдельного «типа дерева» в ядре PostgreSQL нет, и чем заменить привычный по SQL Server hierarchyid. Следом спрашивают, как это ложится на EF Core и как достать поддерево без десятка запросов.
Как отвечать
Сначала отделите тип данных от модели хранения. Специальный тип по сути один:
ltree: расширение из стандартной поставки и ближайший аналогhierarchyid. Путь меток видаroot.dev.backend, операторы@>(предок),<@(потомок),~(шаблонlquery), функцииnlevel()иsubpath(). Под поиск по поддереву нужен GiST-индекс.
Остальное это модели на обычных типах:
- список смежности:
parent_idиWITH RECURSIVE, самый простой вариант для записи; - материализованный путь: строка или массив
int[]с идентификаторами предков; - nested sets: границы
lftиrgt, быстрое чтение и дорогая вставка; - closure table: таблица пар «предок, потомок, глубина», гибкие запросы ценой места;
jsonb: только если дерево живёт как единый документ.
Теперь про .NET. Провайдер Npgsql для EF Core понимает ltree: свойство типа LTree, расширение объявляют через modelBuilder.HasPostgresExtension("ltree"), а вызовы IsAncestorOf, IsDescendantOf и MatchesLQuery транслируются в SQL. Рекурсивный CTE через LINQ не выразить: его пишут руками и выполняют через FromSql для сущностей или Database.SqlQuery<T> для произвольных типов в EF Core 8 и новее. Дерево из плоского списка собирают в памяти через ToLookup(x => x.ParentId).
Где спотыкаются
Относят к «типам для деревьев» CTE, hstore и массивы вообще. CTE это конструкция запроса, hstore плоский словарь, а интервьюер ждёт, что вы разведёте тип, модель хранения и способ запроса.
Грузят дерево цепочкой Include(x => x.Children).ThenInclude(...) или ленивой загрузкой. В первом случае глубина зашита в код и узлы глубже последнего уровня просто не приедут, во втором получается N+1 на каждом уровне.
Переносят hierarchyid один в один. Путь в ltree хранится явно, поэтому перенос ветки означает UPDATE путей у всех потомков, и под часто меняющееся дерево это надо учитывать заранее.