Рекурсивный запрос JPA? - PullRequest
       51

Рекурсивный запрос JPA?

15 голосов
/ 03 сентября 2010

Есть ли в JPA 2 какой-либо механизм для выполнения рекурсивных запросов?

Вот моя ситуация: у меня есть сущность E, которая содержит целое поле x. У него также могут быть дети типа E, сопоставленные через @OneToMany. То, что я хотел бы сделать, это найти E по первичному ключу и получить его значение x вместе со значениями x всех его потомков. Есть ли способ сделать это в одном запросе?

Я использую Hibernate 3.5.3, но я бы предпочел не иметь явных зависимостей от Hibernate API.


РЕДАКТИРОВАТЬ: Согласно этому элементу, Hibernate не имеет эту функцию, или, по крайней мере, не имел в марте. Так что маловероятно, что JPA получит его, но я бы хотел убедиться.

Ответы [ 2 ]

25 голосов
/ 04 сентября 2010

Использование простой модели смежности , где каждая строка содержит ссылку на своих родителей, которые будут ссылаться на другую строку в той же таблице, плохо взаимодействует с JPA.Это связано с тем, что JPA не поддерживает генерацию запросов с использованием предложения Oracle CONNECT BY или стандартного оператора WITH SQL.Без любого из этих двух предложений сделать Смежную модель действительно невозможно.

Однако существует несколько других подходов к моделированию этой проблемы, которые могут быть применены к этой проблеме.Первой является Материализованная модель пути .Здесь полный путь к узлу сведен в один столбец.Определение таблицы расширяется следующим образом:

CREATE TABLE node (id INTEGER,
                   path VARCHAR, 
                   parent_id INTEGER REFERENCES node(id));

Вставка дерева узлов выглядит примерно так:

INSERT INTO node VALUES (1, '1', NULL);  -- Root Node
INSERT INTO node VALUES (2, '1.2', 1);   -- 1st Child of '1'
INSERT INTO node VALUES (3, '1.3', 1);   -- 2nd Child of '1'
INSERT INTO node VALUES (4, '1.3.4', 3); -- Child of '3'

Таким образом, чтобы получить узел '1' и всех его дочерних элементов,запрос:

SELECT * FROM node WHERE id = 1 OR path LIKE '1.%';

Чтобы отобразить это в JPA, просто сделайте столбец 'path' атрибутом вашего постоянного объекта.Однако вам придется вести бухгалтерский учет, чтобы обновлять поле «путь».JPA / Hibernate не сделает это для вас.Например, если вы переместите узел на другого родителя, вам придется обновить родительскую ссылку и определить новое значение пути из нового родительского объекта.

Другой подход называется Модель вложенного набора , что немного сложнее.Вероятно, лучше всего , описанный его создателем (а не добавленным мной дословно).

Существует третий подход, называемый Nested Interval Model, однако он имеет большую зависимость от реализации хранимых процедур.

Гораздо более полное объяснение этой проблемы описано в главе 7 Искусство SQL .

6 голосов
/ 02 февраля 2016

Лучший ответ в этом посте выглядит для меня как обходной прием.Мне уже приходилось иметь дело с моделями данных, где блестящие инженеры решили, что будет хорошей идеей кодировать древовидные иерархии в полях БД в виде текста, такого как: «Европа | Великобритания | Магазин1 | Джон», и с огромными объемами данных в этих таблицах.,Не удивительно, что производительность запроса в форме MyHackedTreeField LIKE «parentHierharchy%», где убийцы.Решение проблемы такого типа в конечном итоге требует создания в памяти кеша дерева hiearchies и многих других ...

Если вам нужно выполнить рекурсивный запрос, а объем данных не велик ... сделайте вашу жизнь прощеи просто загрузите поля БД, необходимые для запуска вашего плана.И код вашей рекурсии в Java.Не делайте это в БД, если у вас нет веских причин для этого.

И даже если объем данных у вас большой, вы, скорее всего, можете разделить вашу проблему на независимые рекурсивные пакеты дерева и обработать его.те по одному без необходимости загружать все данные сразу.

...