Nestjs Sequelize注入多个Repository如何简化重复代码?
首先明确:不推荐在函数内手动new实例化Repository的写法
原因如下:
- 手动实例化的实例脱离Nest的IoC容器管理,若Repository后续依赖其他配置/服务,需要自行维护依赖链,反而增加维护成本
- 不利于单元测试,无法通过Nest的依赖注入机制便捷替换为Mock实例
- 会导致同一Repository被多次实例化,产生不必要的性能开销
简化实现方案
方案1:批量注册Provider(适配你当前自定义TOKEN的写法)
你可以统一维护所有Repository的映射关系,批量生成Provider,省去逐一定义的重复代码:
- 新增配置文件
src/constants/repositories.ts,统一维护所有Repository的Token与模型对应关系:
import Users from 'xxx/Users.model' import UserStores from 'xxx/UserStores.model' import Stores from 'xxx/Stores.model' export const REPOSITORY_MAP = { USER_REPOSITORY: Users, USERSTORE_REPOSITORY: UserStores, STORE_REPOSITORY: Stores } as const export type RepositoryToken = keyof typeof REPOSITORY_MAP
- 在
users.module.ts中批量生成Provider:
import { REPOSITORY_MAP } from '../constants/repositories'; @Module({ controllers: [UsersController], providers: [ UsersService, // 批量生成所有Repository Provider,无需逐一定义 ...Object.entries(REPOSITORY_MAP).map(([token, model]) => ({ provide: token, useValue: model })) ], exports: [UsersService], })
后续新增Repository仅需要在REPOSITORY_MAP中添加一行配置即可,无需修改Module代码。
方案2:使用ORM官方Nest集成包的内置注入能力(推荐)
如果你用的是Sequelize/TypeORM等ORM框架,官方的Nest集成包已经提供了内置的模型注入能力,不需要自定义TOKEN和手动注册Provider:
以@nestjs/sequelize为例,users.services.ts直接简化为:
import { InjectModel } from '@nestjs/sequelize' import Users from 'xxx/Users.model' import UserStores from 'xxx/UserStores.model' import Stores from 'xxx/Stores.model' export class UsersService { constructor( @InjectModel(Users) private readonly userRepository: typeof Users, @InjectModel(UserStores) private readonly userStoresRepository: typeof UserStores, @InjectModel(Stores) private readonly storesRepository: typeof Stores, ) {} async getAllUsers(): Promise<Users[]> { const result = await this.userRepository.findAll<Users>({ include: [ { model: this.userStoresRepository, include: [this.StoresRepository] }, ] }); return result; } }
这种方案完全省去了你自定义TOKEN、手动注册Provider的代码,是最符合Nest生态规范的写法。
方案3:封装统一Repository获取服务(适合不想在构造函数注入多个实例的场景)
如果希望进一步减少构造函数的注入代码,可以封装一个通用的Repository服务,仅注入这一个服务即可获取所有Repository实例:
- 实现通用Repository服务:
import { Injectable } from '@nestjs/common' import { REPOSITORY_MAP } from '../constants/repositories' @Injectable() export class RepositoryService { getRepository<T extends keyof typeof REPOSITORY_MAP>(token: T): typeof REPOSITORY_MAP[T] { return REPOSITORY_MAP[token] } }
- 在业务服务中仅注入该服务即可:
export class UsersService { constructor(private readonly repositoryService: RepositoryService) {} async getAllUsers(): Promise<Users[]> { const userRepository = this.repositoryService.getRepository('USER_REPOSITORY') const userStoresRepository = this.repositoryService.getRepository('USERSTORE_REPOSITORY') const storesRepository = this.repositoryService.getRepository('STORE_REPOSITORY') return userRepository.findAll<Users>({ include: [{ model: userStoresRepository, include: [storesRepository] }] }) } }
注意该方案的缺点是单元测试时需要Mock整个Repository服务,灵活性略低于直接注入对应Repository。
内容的提问来源于stack exchange,提问作者Devb
相关产品推荐
相关产品推荐

