树实体
TypeORM支持用于存储树结构的Adjacency列表和Closure表模式。 要了解有关层次结构表的更多信息,请查看this awesome presentation by Bill Karwin

邻接清单

邻接列表是一个具有自引用的简单模型。 这种方法的好处是简单,缺点是由于连接限制,您无法一次性加载整个树结构。 要了解有关邻接列表的好处和用途的更多信息,请参阅 this article by Matthew Schinckel.
例如::
1
import {Entity, Column, PrimaryGeneratedColumn, ManyToOne, OneToMany} from "typeorm";
2
3
@Entity()
4
export class Category {
5
6
@PrimaryGeneratedColumn()
7
id: number;
8
9
@Column()
10
name: string;
11
12
@Column()
13
description: string;
14
15
@ManyToOne(type => Category, category => category.children)
16
parent: Category;
17
18
@OneToMany(type => Category, category => category.parent)
19
children: Category[];
20
}
21
Copied!

嵌套集

嵌套集是在数据库中存储树结构的另一种模式。 它对读取非常有效,但对写入不利。 且不能在嵌套集中有多个根。 例如:
1
import {Entity, Tree, Column, PrimaryGeneratedColumn, TreeChildren, TreeParent, TreeLevelColumn} from "typeorm";
2
3
@Entity()
4
@Tree("nested-set")
5
export class Category {
6
7
@PrimaryGeneratedColumn()
8
id: number;
9
10
@Column()
11
name: string;
12
13
@TreeChildren()
14
children: Category[];
15
16
@TreeParent()
17
parent: Category;
18
}
Copied!

物化路径(又名路径枚举)

物化路径(也称为路径枚举)是在数据库中存储树结构的另一种模式。 它简单有效。 例如:
1
import {Entity, Tree, Column, PrimaryGeneratedColumn, TreeChildren, TreeParent, TreeLevelColumn} from "typeorm";
2
3
@Entity()
4
@Tree("materialized-path")
5
export class Category {
6
7
@PrimaryGeneratedColumn()
8
id: number;
9
10
@Column()
11
name: string;
12
13
@TreeChildren()
14
children: Category[];
15
16
@TreeParent()
17
parent: Category;
18
}
Copied!

闭合表

闭合表以特殊方式在单独的表中存储父和子之间的关系。 它在读取和写入方面都很有效。 例如:
1
import {Entity, Tree, Column, PrimaryGeneratedColumn, TreeChildren, TreeParent, TreeLevelColumn} from "typeorm";
2
3
@Entity()
4
@Tree("closure-table")
5
export class Category {
6
7
@PrimaryGeneratedColumn()
8
id: number;
9
10
@Column()
11
name: string;
12
13
@TreeChildren()
14
children: Category[];
15
16
@TreeParent()
17
parent: Category;
18
}
Copied!

使用树实体

要使绑定树实体彼此关系,将其父项设置为子实体并保存它们很重要 例如:
1
const manager = getManager();
2
3
const a1 = new Category("a1");
4
a1.name = "a1";
5
await manager.save(a1);
6
7
const a11 = new Category();
8
a11.name = "a11";
9
a11.parent = a1;
10
await manager.save(a11);
11
12
const a12 = new Category();
13
a12.name = "a12";
14
a12.parent = a1;
15
await manager.save(a12);
16
17
const a111 = new Category();
18
a111.name = "a111";
19
a111.parent = a11;
20
await manager.save(a111);
21
22
const a112 = new Category();
23
a112.name = "a112";
24
a112.parent = a11;
25
await manager.save(a112);
Copied!
加载树时使用TreeRepository:
1
const manager = getManager();
2
const trees = await manager.getTreeRepository(Category).findTrees();
Copied!
trees 如下:
1
[{
2
"id": 1,
3
"name": "a1",
4
"children": [{
5
"id": 2,
6
"name": "a11",
7
"children": [{
8
"id": 4,
9
"name": "a111"
10
}, {
11
"id": 5,
12
"name": "a112"
13
}]
14
}, {
15
"id": 3,
16
"name": "a12"
17
}]
18
}]
Copied!
还有其他一些特殊的方法可以处理树形实体,比如TreeRepository
  • findTrees - 返回数据库中所有树,包括所有子项,子项的子项等。
1
const treeCategories = await repository.findTrees();
2
// 返回包含子类别的根类别
Copied!
  • findRoots - 根节点是没有祖先的实体。 找到所有根节点但不加载子节点。
1
const rootCategories = await repository.findRoots();
2
// 返回没有子类别的根类别
Copied!
  • findDescendants - 获取给定实体的所有子项(后代)。 将它们全部返回到数组中。
1
const childrens = await repository.findDescendants(parentCategory);
2
// 返回parentCategory的所有直接子类别(没有其嵌套类别)
Copied!
  • findDescendantsTree - 获取给定实体的所有子项(后代)。
1
const childrensTree = await repository.findDescendantsTree(parentCategory);
2
// 返回parentCategory的所有直接子类别(及其嵌套类别)
Copied!
  • createDescendantsQueryBuilder - 创建用于获取树中实体的后代的查询构建器。
1
const childrens = await repository
2
.createDescendantsQueryBuilder("category", "categoryClosure", parentCategory)
3
.andWhere("category.type = 'secondary'")
4
.getMany();
Copied!
  • countDescendants - 获取实体的后代数。
1
const childrenCount = await repository.countDescendants(parentCategory);
Copied!
  • findAncestors - 获取给定实体的所有父(祖先)。 将它们全部返回到数组中。
1
const parents = await repository.findAncestors(childCategory);
2
// 返回所有直接childCategory的父类别(和"parent 的 parents")
Copied!
  • findAncestorsTree - Gets all parent (ancestors) of the given entity. Returns them in a tree - nested into each other.
1
const parentsTree = await repository.findAncestorsTree(childCategory);
2
// 返回所有直接childCategory的父类别 (和 "parent 的 parents")
Copied!
  • createAncestorsQueryBuilder - 创建用于获取树中实体的祖先的查询构建器。
1
const parents = await repository
2
.createAncestorsQueryBuilder("category", "categoryClosure", childCategory)
3
.andWhere("category.type = 'secondary'")
4
.getMany();
Copied!
  • countAncestors - 获取实体的祖先数。
1
const parentsCount = await repository.countAncestors(childCategory);
Copied!
Last modified 1mo ago