Ответ
В Java иерархические структуры (деревья) обычно представляют с помощью рекурсивных классов.
class TreeNode<T> {
T data;
List<TreeNode<T>> children = new ArrayList<>();
public TreeNode(T data) {
this.data = data;
}
public void addChild(TreeNode<T> child) {
children.add(child);
}
// Рекурсивный обход дерева (DFS)
public void traverse() {
System.out.println(data);
for (TreeNode<T> child : children) {
child.traverse();
}
}
}
// Использование
TreeNode<String> root = new TreeNode<>("Root");
root.addChild(new TreeNode<>("Child 1"));
root.traverse();
В SQL существует несколько паттернов для хранения иерархий:
- Adjacency List (Список смежности): Каждая запись хранит ссылку на родителя (
parent_id). Для выборки поддерева требуются рекурсивные запросы (WITH RECURSIVEв PostgreSQL,CONNECT BYв Oracle). - Nested Sets (Вложенные множества): Каждый узел имеет границы
leftиright. Позволяет быстро выбирать поддеревья без рекурсии, но сложен в модификации. - Materialized Path (Материализованный путь): Путь от корня хранится в виде строки (например,
1.5.12). Легко читается и фильтруется поLIKE.
В JPA/Hibernate для Adjacency List используются аннотации @ManyToOne и @OneToMany.
@Entity
class Category {
@Id
private Long id;
private String name;
@ManyToOne
@JoinColumn(name = "parent_id")
private Category parent;
@OneToMany(mappedBy = "parent")
private List<Category> children;
}