Меня эта тема интересовала довольно давно, поэтому, пожалуйста, не принимайте все, что я говорю, как должное (возможно, кто-то с большим опытом работы NHibernate
может исправить меня в случае, если я ошибаюсь).
В прошлый раз, когда я проверял, описанная ситуация была довольно проблемной, поскольку Nhibernate
генерировал отдельные запросы для каждого level
дочерних объектов. Если вы заранее знаете, что ваша глубина дерева не будет слишком большой, чем, вероятно, вы могли бы жить без eager loading
детей ... Но если ваша структура не ограничена в глубине, вы, вероятно, должны искать альтернативы.
Если вы используете SqlServer
Одним из решений, которое я нашел довольно простым для реализации, было использование recursive self-join
/ CTE
. Это решение включает переключение на stored-procedures
в качестве источника запроса и повторное создание иерархии вручную в коде. Чтобы получить целое дерево, вам нужен только один запрос в БД (который может включать в себя все виды фильтров и подзапросов + упорядочение), и вы все равно можете повторно использовать сопоставления NHibernate
для всех операций CRUD
. Один из недостатков этого решения заключается в том, что впоследствии вам придется поддерживать код запроса на стороне базы данных (изменения столбца и отображения и т.
Модифицированный алгоритм обхода дерева предзаказа
Это мое ideal
решение для сохранения дерева, поскольку оно не требует stored-procedures
и может быть идеально интегрировано с NHibernate
и Criteria API
(что для меня является огромным преимуществом, поскольку я могу свободно создавать расширенные и многоразовые фильтры в коде). С точки зрения производительности все варианты выбора почти бесплатны - вы перемещаете баланс в сторону операций вставки, обновления и удаления, так как вам нужно пересчитать дерево при каждом изменении - но это можно сделать с помощью hql
, например, так ( псевдо-код):
HQLNamedQuery hql = new HQLNamedQuery();
hql.Query = "UPDATE " + typeof(THierarchy).FullName +
" SET TraversalLeft = (TraversalLeft + :traversalChange) " +
" WHERE BaseNodeId = :baseNodeId AND TraversalLeft > :minTr AND TraversalLeft <= :maxTr";
Мне удалось реализовать все виды операций с использованием этой техники (например, добавление, добавление диапазона, перемещение, изменение порядка, получение потомков, получение предков, подсчет потомков и т. Д.), И я должен сказать, что как только вы получите Основной принцип, вы можете идеально интегрировать его в разные проекты.
Ссылка на статью, которая подтолкнула меня к этой теме (к сожалению, NHibernate
не используется):
http://weblogs.asp.net/aghausman/archive/2009/03/16/storing-retrieving-hierarchical-data-in-sql-server-database.aspx
Отображение дерева в NHibernate
Может быть, вам стоит взглянуть на этот пост (точная часть начинается с An alternative approach
):
http://nhibernate.hibernatingrhinos.com/16/how-to-map-a-tree-in-nhibernate
Это в основном сводится к добавлению двух дополнительных коллекций к вашему отображению: Ancestors
и Descendants
и выполнению трех запросов: основного запроса, загрузки предков и загрузки потомков - это должно препятствовать выполнению NHibernate дополнительных запросов при доступе к дочерним узлам.
Надеюсь, это поможет.