Это хороший вопрос, но без особых подробностей трудно говорить о «лучшем» решении.
Вы можете сопоставить это с абстрактным вопросом о том, как хранить n-арное дерево в реляционной базе данных.
Вот некоторые переменные, которые влияют на проблему:
- Каков общий размер структуры каталогов?
- Сколько отдельных виртуальных машин выполняет запись в структуру?
- Являются ли операции перемещения частыми?
- Является ли сбой всего поддерева важной операцией?
- Поддерживает ли ваша база данных обход дерева или вам нужно решение, которое работает с любой разумной реляционной базой данных?
Далее предполагается, что в вашей базе данных нет специальных положений для выполнения обходов дерева.
Для n-арных деревьев существуют две модели чистой персистентности.
Первый - просто написать каждый узел с родительской ссылкой:
| NodeId | ParentId | Name | ....
|--------|----------|------------|-----
Этот подход упрощает перемещение папки, но удаляет, запросы ко всем вложенным подпапкам и поиск корня становятся дорогостоящими.
Вторая чистая модель - сохранять все родственные отношения отдельно от подробностей папки
| NodeId | Name | ....
|--------|----------|------
...
| NodeId | AncestorId | Distance |
|--------|------------|----------|
...
Здесь папка / food / dairy / cheese / cheddar выдаст
| NodeId | Name |
|--------|----------|
| #0 | (root) |
| #1 | food |
| #2 | dairy |
| #3 | cheese |
| #4 | cheddar |
| NodeId | AncestorId | Distance |
|--------|------------|----------|
| #1 | #0 | 1 |
| #2 | #0 | 2 |
| #2 | #1 | 1 |
| #3 | #0 | 3 |
| #3 | #1 | 2 |
| #3 | #2 | 1 |
| #4 | #0 | 4 |
| #4 | #1 | 3 |
| #4 | #2 | 2 |
| #4 | #3 | 1 |
Этот подход очень дорог для перемещений, и новый каталог вызывает d
вставок, где d
- расстояние от корня. Но список поддеревьев - это один запрос. Путь предков также является одним запросом; order by Distance desc
позволит вам быстро добраться до корневой и первой папок.
Но, если внимательно прочитать ваш вопрос, вариант первого подхода, просто добавив root, может быть правильным подходом для вас:
| NodeId | ParentId | RootId | Name | ....
|--------|----------|--------|------------|-----
Обратите внимание, что перемещение папки будет дорогостоящим, поскольку вам необходимо определить все вложенные подпапки и обновить RootId всех этих записей.