• 自定义存储库
    • 扩展了标准存储库的定制存储库
    • 扩展了标准AbstractRepository的自定义存储库
    • 没有扩展的自定义存储库
    • 在事务中使用自定义存储库或为什么自定义存储库不能是服务

    自定义存储库

    你可以创建一个自定义存储库,其中应包含使用数据库的方法。 通常为单个实体创建自定义存储库,并包含其特定查询。 比如,假设我们想要一个名为findByName(firstName:string,lastName:string)的方法,它将按给定的 first 和 last names 搜索用户。 这个方法的最好的地方是在Repository,所以我们可以这样称呼它userRepository.findByName(...)。 你也可以使用自定义存储库来实现此目的。

    有几种方法可以创建自定义存储库。

    扩展了标准存储库的定制存储库

    创建自定义 repository 的第一种方法是扩展Repository。 例如:

    1. import { EntityRepository, Repository } from "typeorm";
    2. import { User } from "../entity/User";
    3. @EntityRepository(User)
    4. export class UserRepository extends Repository<User> {
    5. findByName(firstName: string, lastName: string) {
    6. return this.findOne({ firstName, lastName });
    7. }
    8. }

    然后你可以这样使用它:

    1. import { getCustomRepository } from "typeorm";
    2. import { UserRepository } from "./repository/UserRepository";
    3. const userRepository = getCustomRepository(UserRepository); // 或connection.getCustomRepository或manager.getCustomRepository()
    4. const user = userRepository.create(); // 和 const user = new User();一样
    5. user.firstName = "Timber";
    6. user.lastName = "Saw";
    7. await userRepository.save(user);
    8. const timber = await userRepository.findByName("Timber", "Saw");

    如你所见,你也可以使用getCustomRepository 获取 repository, 并且可以访问在其中创建的任何方法以及标准实体 repository 中的任何方法。

    扩展了标准AbstractRepository的自定义存储库

    创建自定义 repository 的第二种方法是扩展AbstractRepository

    1. import { EntityRepository, AbstractRepository } from "typeorm";
    2. import { User } from "../entity/User";
    3. @EntityRepository(User)
    4. export class UserRepository extends AbstractRepository<User> {
    5. createAndSave(firstName: string, lastName: string) {
    6. const user = new User();
    7. user.firstName = firstName;
    8. user.lastName = lastName;
    9. return this.manager.save(user);
    10. }
    11. findByName(firstName: string, lastName: string) {
    12. return this.repository.findOne({ firstName, lastName });
    13. }
    14. }

    然后你可以这样使用它:

    1. import { getCustomRepository } from "typeorm";
    2. import { UserRepository } from "./repository/UserRepository";
    3. const userRepository = getCustomRepository(UserRepository); // or connection.getCustomRepository or manager.getCustomRepository()
    4. await userRepository.createAndSave("Timber", "Saw");
    5. const timber = await userRepository.findByName("Timber", "Saw");

    这种类型的存储库与前一个存储库之间的区别在于它没有公开Repository所具有的所有方法。 AbstractRepository没有任何公共方法,它只有受保护的方法,比如managerrepository,你可以在自己的公共方法中使用它们。 如果你不希望将标准Repository所有方法公开给 public,那么扩展AbstractRepository将非常有用。

    没有扩展的自定义存储库

    创建存储库的第三种方法是不扩展任何东西, 但是需要定义一个总是接受实体管理器(entity manager)实例的构造函数:

    1. import { EntityRepository, Repository, EntityManager } from "typeorm";
    2. import { User } from "../entity/User";
    3. @EntityRepository()
    4. export class UserRepository {
    5. constructor(private manager: EntityManager) {}
    6. createAndSave(firstName: string, lastName: string) {
    7. const user = new User();
    8. user.firstName = firstName;
    9. user.lastName = lastName;
    10. return this.manager.save(user);
    11. }
    12. findByName(firstName: string, lastName: string) {
    13. return this.manager.findOne(User, { firstName, lastName });
    14. }
    15. }

    然后你可以这样使用它:

    1. import { getCustomRepository } from "typeorm";
    2. import { UserRepository } from "./repository/UserRepository";
    3. const userRepository = getCustomRepository(UserRepository); // 或者 connection.getCustomRepository 或者 manager.getCustomRepository()
    4. await userRepository.createAndSave("Timber", "Saw");
    5. const timber = await userRepository.findByName("Timber", "Saw");

    这种类型的存储库不会扩展任何东西,你只需要定义一个必须接受EntityManager的构造函数。 然后在存储库方法中的任何位置使用它。 此外,这种类型的存储库不绑定到特定实体,因此你可以使用其中的多个实体进行操作。

    在事务中使用自定义存储库或为什么自定义存储库不能是服务

    自定义存储库不能是服务,因为应用程序中没有自定义存储库的单个实例(就像常规存储库或实体管理器一样)。 除了您的应用程序中可能存在多个连接(实体管理器和存储库不同)之外,存储库和管理器在事务中也是不同的。

    例如:

    1. await connection.transaction(async manager => {
    2. // 在事务中你必须使用事务提供的管理器实例而不能使用全局管理器、存储库或自定义存储库,
    3. // 因为这个管理器是独占的和事务性的,
    4. // 如果让我们自定义存储库作为服务,它的一个"manager"属性应该 是EntityManager的唯一实例,但没有全局的EntityManager实例,并且也不可能有。
    5. // 这就是为什么自定义管理器特定于每个EntityManager而不能是服务。
    6. // 这也提供了在事务中使用自定义存储库而不会出现什么问题:
    7. const userRepository = manager.getCustomRepository(UserRepository); // 不要在这里使用全局的getCustomRepository!
    8. await userRepository.createAndSave("Timber", "Saw");
    9. const timber = await userRepository.findByName("Timber", "Saw");
    10. });