• 树实体
    • 邻接清单
    • 嵌套集
    • 物化路径(又名路径枚举)
    • 闭合表
    • 使用树实体

    树实体

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

    邻接清单

    邻接列表是一个具有自引用的简单模型。 这种方法的好处是简单,缺点是由于连接限制,您无法一次性加载整个树结构。 要了解有关邻接列表的好处和用途的更多信息,请参阅 this article by Matthew Schinckel.

    例如::

    1. import {Entity, Column, PrimaryGeneratedColumn, ManyToOne, OneToMany} from "typeorm";
    2. @Entity()
    3. export class Category {
    4. @PrimaryGeneratedColumn()
    5. id: number;
    6. @Column()
    7. name: string;
    8. @Column()
    9. description: string;
    10. @ManyToOne(type => Category, category => category.children)
    11. parent: Category;
    12. @OneToMany(type => Category, category => category.parent)
    13. children: Category[];
    14. }

    嵌套集

    嵌套集是在数据库中存储树结构的另一种模式。 它对读取非常有效,但对写入不利。 且不能在嵌套集中有多个根。 例如:

    1. import {Entity, Tree, Column, PrimaryGeneratedColumn, TreeChildren, TreeParent, TreeLevelColumn} from "typeorm";
    2. @Entity()
    3. @Tree("nested-set")
    4. export class Category {
    5. @PrimaryGeneratedColumn()
    6. id: number;
    7. @Column()
    8. name: string;
    9. @TreeChildren()
    10. children: Category[];
    11. @TreeParent()
    12. parent: Category;
    13. }

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

    物化路径(也称为路径枚举)是在数据库中存储树结构的另一种模式。 它简单有效。 例如:

    1. import {Entity, Tree, Column, PrimaryGeneratedColumn, TreeChildren, TreeParent, TreeLevelColumn} from "typeorm";
    2. @Entity()
    3. @Tree("materialized-path")
    4. export class Category {
    5. @PrimaryGeneratedColumn()
    6. id: number;
    7. @Column()
    8. name: string;
    9. @TreeChildren()
    10. children: Category[];
    11. @TreeParent()
    12. parent: Category;
    13. }

    闭合表

    闭合表以特殊方式在单独的表中存储父和子之间的关系。 它在读取和写入方面都很有效。 例如:

    1. import {Entity, Tree, Column, PrimaryGeneratedColumn, TreeChildren, TreeParent, TreeLevelColumn} from "typeorm";
    2. @Entity()
    3. @Tree("closure-table")
    4. export class Category {
    5. @PrimaryGeneratedColumn()
    6. id: number;
    7. @Column()
    8. name: string;
    9. @TreeChildren()
    10. children: Category[];
    11. @TreeParent()
    12. parent: Category;
    13. }

    使用树实体

    要使绑定树实体彼此关系,将其父项设置为子实体并保存它们很重要 例如:

    1. const manager = getManager();
    2. const a1 = new Category("a1");
    3. a1.name = "a1";
    4. await manager.save(a1);
    5. const a11 = new Category();
    6. a11.name = "a11";
    7. a11.parent = a1;
    8. await manager.save(a11);
    9. const a12 = new Category();
    10. a12.name = "a12";
    11. a12.parent = a1;
    12. await manager.save(a12);
    13. const a111 = new Category();
    14. a111.name = "a111";
    15. a111.parent = a11;
    16. await manager.save(a111);
    17. const a112 = new Category();
    18. a112.name = "a112";
    19. a112.parent = a11;
    20. await manager.save(a112);

    加载树时使用TreeRepository:

    1. const manager = getManager();
    2. const trees = await manager.getTreeRepository(Category).findTrees();

    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. }]

    还有其他一些特殊的方法可以处理树形实体,比如TreeRepository

    • findTrees - 返回数据库中所有树,包括所有子项,子项的子项等。
    1. const treeCategories = await repository.findTrees();
    2. // 返回包含子类别的根类别
    • findRoots - 根节点是没有祖先的实体。 找到所有根节点但不加载子节点。
    1. const rootCategories = await repository.findRoots();
    2. // 返回没有子类别的根类别
    • findDescendants - 获取给定实体的所有子项(后代)。 将它们全部返回到数组中。
    1. const childrens = await repository.findDescendants(parentCategory);
    2. // 返回parentCategory的所有直接子类别(没有其嵌套类别)
    • findDescendantsTree - 获取给定实体的所有子项(后代)。
    1. const childrensTree = await repository.findDescendantsTree(parentCategory);
    2. // 返回parentCategory的所有直接子类别(及其嵌套类别)
    • createDescendantsQueryBuilder - 创建用于获取树中实体的后代的查询构建器。
    1. const childrens = await repository
    2. .createDescendantsQueryBuilder("category", "categoryClosure", parentCategory)
    3. .andWhere("category.type = 'secondary'")
    4. .getMany();
    • countDescendants - 获取实体的后代数。
    1. const childrenCount = await repository.countDescendants(parentCategory);
    • findAncestors - 获取给定实体的所有父(祖先)。 将它们全部返回到数组中。
    1. const parents = await repository.findAncestors(childCategory);
    2. // 返回所有直接childCategory的父类别(和"parent 的 parents")
    • 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")
    • createAncestorsQueryBuilder - 创建用于获取树中实体的祖先的查询构建器。
    1. const parents = await repository
    2. .createAncestorsQueryBuilder("category", "categoryClosure", childCategory)
    3. .andWhere("category.type = 'secondary'")
    4. .getMany();
    • countAncestors - 获取实体的祖先数。
    1. const parentsCount = await repository.countAncestors(childCategory);