Стремительная загрузка дерева / иерархий с помощью Nhibernate
Это не вопрос как таковой, я изучал эту тему в течение последних нескольких дней и подумал, что хотел бы поделиться чем-то, что привлекло много разрозненных идей, о которых я читал, и выдвинул свое решение для проблема...
Проблема заключается в стремлении загрузить дочерние объекты n уровня в Nhibernate и в том, что nHibernate не будет знать глубину дерева. Я видел, как это решается с помощью прямого sql и Union All, но, к сожалению, я не смог заставить это работать, обычно потому, что nhibernate не знает, что вы загружали объекты. Поэтому я посмотрел на следующий код для загрузки объекта с использованием критерия
var children = Session.CreateCriteria<MenuNode>()
.SetFetchMode("Children", FetchMode.Eager)
.Add(Expression.Eq("Id", 1))
.List<MenuNode>();
Это будет стремиться загрузить дочерний элемент для идентификатора 1, отсюда вы можете использовать оператор In для загрузки сразу нескольких сущностей. Поэтому мне нужно только обработать все идентификаторы узлов, которые принадлежат этой иерархии, и стремиться загрузить их с помощью оператора In.
Так что, если я создаю родительскую таблицу для иерархии, и каждый узел имеет идентификатор иерархии, то я могу получить список всех идентификаторов узлов для этой иерархии, используя этот hql
var sql = "select Distinct id from Nodes where (HierarchyId = :id) ";
var ids = Session.CreateSQLQuery(sql)
.SetInt32("id", id)
.List();
и отсюда стремятся загрузить всех детей для этого дерева в одиночку, используя
var children = Session.CreateCriteria<MenuNode>()
.SetFetchMode("Children", FetchMode.Eager)
.Add(Expression.In("Id", ids))
.List<MenuNode>();
Единственная проблема в этом заключается в том, что вы не очень загружали уровни первого уровня узлов из родительской таблицы иерархии, что можно сделать обычным образом.
var menu = Session.CreateCriteria<Menu>()
.SetFetchMode("RootNodes", FetchMode.Eager)
.Add(Expression.Eq("Id", id))
.List<Menu>();
Вот и все, в трех SQL-выражениях вы загружали дочерний объект на n уровней. Для дальнейшей оптимизации я использовал мультизапрос, чтобы связать два основных запроса и отправить оба оператора одновременно. Оператор для возврата идентификатора должен выполняться независимо, чтобы вернуть идентификатор, хотя.
Более подробную информацию об использовании MultiCriteria для загрузки можно найти здесь.
Надеюсь, что это поможет кому-то
1 ответ
Я понимаю, что вы не задаете вопрос, но я решил поделиться тем, как я предпочитаю это делать. См. http://ayende.com/Blog/archive/2009/08/28/nhibernate-tips-amp-tricks-efficiently-selecting-a-tree.aspx
return session.CreateCriteria<MenuNode>()
.SetFetchMode("Children", FetchMode.Join)
.SetResultTransformer(new DistinctRootEntityResultTransformer())
.List<MenuNode>();
Я не знаю, достигает ли это всего, что вы намеревались выполнить с помощью вашего подхода, но я нашел, что это очень полезный инструмент при работе с иерархическими данными.