Мы часто сталкиваемся с такими сценариями в разработке проекта: организационная структура предприятия, цепочка ответов на комментарии, категория продукта и другие древовидные структуры. Эта статья сочетает в себе информацию из Интернета и мою собственную практику в проекте, чтобы рассказать о нескольких способах работы с древовидной структурой.
Может быть много знакомых, которые столкнулись с этой проблемой.Первая мысль, что я сохраняю это на каждом куске данных.parent_id
Он может удовлетворить потребности, чтобы его можно было найти слой за слоем, а если написать рекурсивный алгоритм, то можно получить всех его подчиненных или вышестоящих. Это достижимый путь, и мы не будем оценивать плюсы и минусы такого подхода.
Вот несколько распространенных способов борьбы с ним:
- Список смежности
- Таблица закрытия
- Перечисление пути
- Вложенные наборы
В этой статье в основном объясняется перечисление путей (перечисление путей), а другие типы показаны лишь кратко.Если вам нужно знать, вы можете щелкнуть ссылку для просмотра.
-
Подробно объясните таблицу замыканий.у-у-у. Краткое описание.com/afraid/951 не 742 против…
-
Объясняются четыре способаБлог Woohoo.cn на.com/Wujin District 310/Afraid/88…
-
MySQL реализует модель вложенной коллекцииОсобенно Aliyun.com/articles/50…
Список смежности
На следующем рисунке показана организационная структура простой структуры списка смежности, о которой мы говорили ранее.
Как получить данные
- Чтобы получить прямой отдел в организации, нам нужно только запросить по идентификатору организации.
select * from org where parent_id =1;
- Чтобы запросить все организации в организации, вам нужно рекурсивно + зациклить, чтобы получить подчиненные узлы дочерних элементов, внуков и т. д., что примерно записывается следующим образом:
public List<Org> getOrgTree(String parentId){
List<Orgs> resultOrgs = new ArrayList<>();
// 拿到下级组织
List<Org> children = getChildren(parentId);
resultOrgs.addAll(children);
for(Org org :children){
resultOrgs.addAll(getOrgTree(org.parentID));
}
return resultOrgs;
}
Таблица закрытия
Этот метод представлен комментариями к сообщениям, структура данных хлопотная, заимствованнаяу-у-у. Краткое описание.com/afraid/951 не 742 против…На схеме модель базы данных выглядит следующим образом:
![](xiao-files.oss-cn-beijing.aliyuncs.com/picgo/закрытие таблицы (2).png)
предок хранит корневой идентификатор ответа, потомок хранит текущий идентификатор, а хранилище занимает место Теоретически для хранения отношения требуется O (n²) пространства.
-- 父查子,连表查询comment 和 comment_path 拿到4号的评论
select c.* from comment c
left join comment_path cp on (c.id = cp.descendant)
where cp.ancestor = 4 and depth = 1;
-- 查询4号的所有子评论
select c.* from comment c join comment_path cp on (c.id = cp.descendant) where cp.ancestor = 4;
Вложенные наборы
Решение с вложенным набором хранит информацию в каждом узле, каждый из которых соответствует набору своих потомков, а не непосредственному родителю узла.
В дизайне вложенных наборов манипуляции с деревом, вставка и перемещение узлов часто более сложны, чем в других моделях.
При вставке нового узла необходимо пересчитать все левые и правые значения, превышающие левое значение нового узла.
Вложенные множества слишком сложны, и я не до конца в них разбираюсь, в этой статье мы не будем их подробно представлять. может относиться кMySQL реализует модель вложенной коллекции
Перечисление пути
Этот метод берет в качестве примера организационную таблицу в проекте.Отличие от перечисления пути заключается в том, что вместо пути используется org_num.
В проекте мы договорились, что числовая длина каждого уровня равна 2, максимальный уровень — 20, количество дочерних узлов на уровне — 99, а максимальное количество хранимых узлов: 2 в 19-й степени узлов.
Иерархия выглядит следующим образом:
Несколько способов манипулирования данными
Соглашение orgNum — это номер узла, orgLen — длина номера узла.
- Получить несколько слоев дочерних узлов узла
-- 在java代码中根据当前节点orgNum得到 orgLen和maxLength
select * from orgs where org_num like '#{orgNum}%' and length(org_num) > #{orgLen} and length(org_num) <=#{maxLength}
- Получить все дочерние узлы узла
select * from orgs where org_num like '#{orgNum}%' and length(org_num) > #{orgLen}
- Получите родительский узел или найдите родительский узел на несколько слоев выше.
-- 先在java代码中的根据当前节点orgNum, 计算得出要找节点的orgNum,
select * from orgs where org_num = #{orgNum}
- удалить организационную структуру
-- 删除所有子节点,和查询所有子节点类型
delete from orgs where org_num like '#{orgNum}%' and length(org_num) > #{orgLen}
- Движение узла
// 节点移动,更新当前节点的org_num以及所有下级子节点的org_num
// 如果牵扯到节点排序,则除了更新当前节点的orgNum外,还要考虑要移动到的同级节点的orders
- Построение организационного дерева
// 先从数据库中得到某个节点本身rootOrg及所有下级节点OrgList
private OrgTreeDTO orgTreeGenerate(List<Org> OrgList, Org rootNode, Org parent) {
List<Org> subNodes = OrgList.stream().filter(x ->
x.getOrgNum().startsWith(rootNode.getOrgNum())
&& x.getOrgNum().length() == rootNode.getOrgNum().length() + OrgConst.ORG_NODE_LENGTH
&& !x.getId().equals(rootNode.getId())
).collect(Collectors.toList());
OrgTreeDTO orgTreeDTO = new OrgTreeDTO().setId(rootNode.getId())
.setName(rootNode.getName())
.setOrders(rootNode.getOrders())
.setType(rootNode.getType())
.setChildren(subNodes.stream().map(x ->
orgTreeGenerate(OrgList, x,rootNode)
).collect(Collectors.toList()));
if(!ObjectUtils.isEmpty(parent)){
orgTreeDTO.setParentId(parent.getId())
.setParentName(parent.getName());
}
return orgTreeDTO;
}
Вышеупомянутые методы могут почти удовлетворить большинство потребностей в корректировке организационной структуры.
Преимущество этого метода в том, что нужные данные можно получить из базы данных с помощью простого запроса, а конкретная сборка обрабатывается в java-коде.
Недостаток Если уровень слишком глубокий,org_num
Это будет становиться все длиннее и длиннее и влиять на эффективность запроса, поэтому глубина узла в проекте ограничена 20, что может удовлетворить практически все данные организационной структуры.
Суммировать
Это конец этой статьи.Если у вас есть похожие идеи дизайна или вопросы, добро пожаловать в обсуждение.
Ссылка на блог команды, добро пожаловать, чтобы нажать
Теория уточняет направление практики, а практика выявляет достоверность теории.