• 与 Relations 结合

    与 Relations 结合

    RelationQueryBuilderQueryBuilder的一种允许你使用关系来查询的特殊类型。通过使用你可以在数据库中将实体彼此绑定,而无需加载任何实体,或者可以轻松地加载相关实体。例如:

    例如,我们有一个Post实体,它与Category有一个多对多的关系,叫做categories。让我们为这种多对多关系添加一个新 category:

    1. import { getConnection } from "typeorm";
    2. await getConnection()
    3. .createQueryBuilder()
    4. .relation(Post, "categories")
    5. .of(post)
    6. .add(category);

    这段代码相当于:

    1. import { getManager } from "typeorm";
    2. const postRepository = getRepository(Post);
    3. const post = await postRepository.findOne(1, { relations: ["categories"] });
    4. post.categories.push(category);
    5. await postRepository.save(post);

    但是这样使用第一种方式效率更高,因为它执行的操作数量最少,并且绑定数据库中的实体,这比每次都调用save这种笨重的方法简化了很多。

    此外,这种方法的另一个好处是不需要在 pushing 之前加载每个相关实体。例如,如果你在一个 post 中有一万个 categories,那么在此列表中添加新 posts 可能会产生问题,因为执行此操作的标准方法是加载包含所有一万个 categories 的 post,push 一个新 category 然后保存。 这将会导致非常高的性能成本,而且基本上不适用于生产环境。但是,使用RelationQueryBuilder则解决了这个问题。

    此外,当进行绑定时,可以不需要使用实体,只需要使用实体 ID 即可。例如,让我们在 id 为 1 的 post 中添加 id = 3 的 category:

    1. import { getConnection } from "typeorm";
    2. await getConnection()
    3. .createQueryBuilder()
    4. .relation(Post, "categories")
    5. .of(1)
    6. .add(3);

    如果你使用了复合主键,则必须将它们作为 id 映射传递,例如:

    1. import { getConnection } from "typeorm";
    2. await getConnection()
    3. .createQueryBuilder()
    4. .relation(Post, "categories")
    5. .of({ firstPostId: 1, secondPostId: 3 })
    6. .add({ firstCategoryId: 2, secondCategoryId: 4 });

    也可以按照添加实体的方式删除实体:

    1. import { getConnection } from "typeorm";
    2. // 此代码从给定的post中删除一个category
    3. await getConnection()
    4. .createQueryBuilder()
    5. .relation(Post, "categories")
    6. .of(post) // 也可以使用post id
    7. .remove(category); // 也可以只使用category ID

    添加和删除相关实体针对多对多一对多关系。对于一对一多对一关系,请使用set代替:

    1. import { getConnection } from "typeorm";
    2. // 此代码set给定post的category
    3. await getConnection()
    4. .createQueryBuilder()
    5. .relation(Post, "categories")
    6. .of(post) // 也可以使用post id
    7. .set(category); // 也可以只使用category ID

    如果要取消设置关系(将其设置为 null),只需将null传递给set方法:

    1. import { getConnection } from "typeorm";
    2. // 此代码取消设置给定post的category
    3. await getConnection()
    4. .createQueryBuilder()
    5. .relation(Post, "categories")
    6. .of(post) // 也可以使用post id
    7. .set(null);

    除了更新关系外,关系查询构建器还允许你加载关系实体。例如,假设在Post实体内部,我们有多对多的categories关系和多对一的user关系,为加载这些关系,你可以使用以下代码:

    1. import { getConnection } from "typeorm";
    2. const post = await getConnection().manager.findOne(Post, 1);
    3. post.categories = await getConnection()
    4. .createQueryBuilder()
    5. .relation(Post, "categories")
    6. .of(post) // 也可以使用post id
    7. .loadMany();
    8. post.author = await getConnection()
    9. .createQueryBuilder()
    10. .relation(User, "user")
    11. .of(post) // 也可以使用post id
    12. .loadOne();