Делаем это с помощью SQL
Для моего ответа я собираюсь предположить, что seq
используется для упорядочения братьев и сестер в иерархии вашего меню, и что ваши примерные данные неверны (два брата не могутимеют одинаковое значение seq
, т.е. должно быть UNIQUE (pid, seq)
. Итак, я поработаю с этими примерами данных (INT
идентификаторы для простоты):
INSERT INTO menu (id, pid, name, seq)
VALUES
(1, null, 'Menu 1', 1),
(2, null, 'Menu 2', 2),
(3, null, 'Menu 3', 3),
(4, 1, 'Sub Menu 1', 1),
(5, null, 'Menu 1', 9);
Вам понадобитсярекурсивный запрос для этого, используя WITH clause
. В SQL:
WITH RECURSIVE m AS (
SELECT
id,
ARRAY[seq] AS path,
name, 1 AS level,
'- ' || name AS display
FROM menu
WHERE pid IS NULL
UNION ALL
SELECT
menu.id,
path || seq,
menu.name,
m.level + 1 AS level,
repeat(' ', m.level) || '- ' || menu.name
FROM menu JOIN m ON m.id = menu.pid
)
SELECT *
FROM m
ORDER BY path;
Вывод запроса можно увидеть здесь . Это:
id |path |name |level |display |
---|------|-----------|------|---------------|
1 |{1} |Menu 1 |1 |- Menu 1 |
4 |{1,1} |Sub Menu 1 |2 | - Sub Menu 1 |
2 |{2} |Menu 2 |1 |- Menu 2 |
3 |{3} |Menu 3 |1 |- Menu 3 |
5 |{9} |Menu 1 |1 |- Menu 1 |
Конечно, есть и другие способы достижения того же результата. Объяснения столбцов:
id
: идентификатор исходного пункта меню path
: Путь, ведущий к любому данному элементу меню (массив объединенных значений seq
, при условии, что они уникальны для pid
) name
: исходное имя пункта меню level
: уровень рекурсии или вложенности (полезен для заполнения) display
: отображение элемента меню с отступами согласно вашему вопросу
Выполнение с помощью jOOQ
Теперь вам просто нужно перевести вышеприведенное в запрос jOOQ.
При условии, что эти статические операции импорта (как всегда):
import static org.jooq.impl.DSL.*;
import static com.example.generated.Table.*;
следующим образом:
Field<Integer[]> path = array(MENU.SEQ).as("path");
Field<Integer> level = inline(1).as("level");
Field<String> display = inline("- ").concat(MENU.NAME).as("display");
Table<?> m = name("m").as(
select(MENU.ID, path, MENU.NAME, level, display)
.from(MENU)
.where(MENU.PID.isNull())
.unionAll(
select(
MENU.ID,
PostgresDSL.arrayAppend(path, MENU.SEQ),
MENU.NAME,
level.add(inline(1)),
repeat(inline(" "), level).concat(inline("- ")).concat(MENU.NAME))
.from(MENU)
.join(table(name("m"))).on(field(name("m", "id"), Integer.class).eq(MENU.PID)))
);
ctx.selectFrom(m).orderBy(path).fetch();