NestJS 9(TypeORM 3.+)中如何扩展TypeORM Repository
NestJS 9 + TypeORM 3.x 自定义仓储实现方案
TypeORM 3.0 移除旧版@EntityRepository装饰器后,@nestjs/typeorm@9.x版本提供了适配的官方实现路径,完全可以把所有ORM相关逻辑收敛在仓储层,不需要把数据库操作堆在服务层。
首先确认依赖版本匹配:
typeorm版本 >= 3.0.0@nestjs/typeorm版本 >= 9.0.0
方案1:封装式实现(官方推荐)
这种方式不依赖继承,通过注入原生Repository实例扩展能力,符合TypeORM 3.x的设计规范。
- 编写自定义仓储类
import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { User } from './entities/user.entity'; @Injectable() export class UsersRepo { constructor( @InjectRepository(User) private readonly baseRepo: Repository<User>, ) {} // 按需绑定原生Repository方法,不需要重复实现基础逻辑 create = this.baseRepo.create.bind(this.baseRepo); save = this.baseRepo.save.bind(this.baseRepo); find = this.baseRepo.find.bind(this.baseRepo); findOne = this.baseRepo.findOne.bind(this.baseRepo); delete = this.baseRepo.delete.bind(this.baseRepo); update = this.baseRepo.update.bind(this.baseRepo); // 自定义ORM方法:复杂查询、聚合等逻辑统一写在这里 async getUsersCreatedAfter(time: Date) { return this.baseRepo .createQueryBuilder('user') .where('user.createdAt > :time', { time }) .getMany(); } async countByRole(role: string) { return this.baseRepo.count({ where: { role } }); } }
- 在对应业务模块中注册仓储
import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { User } from './entities/user.entity'; import { UsersRepo } from './users.repo'; import { UsersService } from './users.service'; @Module({ imports: [TypeOrmModule.forFeature([User])], providers: [UsersRepo, UsersService], exports: [UsersRepo], }) export class UsersModule {}
- 在服务层直接注入使用,和旧版本体验完全一致
import { Injectable } from '@nestjs/common'; import { UsersRepo } from './users.repo'; @Injectable() export class UsersService { constructor(private readonly usersRepo: UsersRepo) {} async queryRecentUsers() { // 可直接调用原生Repository方法 const allUsers = await this.usersRepo.find(); // 也可调用自定义仓储方法 const recentUsers = await this.usersRepo.getUsersCreatedAfter(new Date('2024-01-01')); return recentUsers; } }
方案2:继承式实现(兼容旧版写法习惯)
如果更习惯旧版本继承Repository的写法,可以直接继承原生Repository类,在构造函数中初始化父类参数即可,不需要额外引入废弃装饰器。
import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository, DataSource } from 'typeorm'; import { User } from './entities/user.entity'; @Injectable() export class UsersRepo extends Repository<User> { constructor( @InjectRepository(User) private dataSource: DataSource, ) { super(User, dataSource.createEntityManager(), dataSource.createQueryRunner()); } // 直接通过this调用原生Repository方法,同时编写自定义逻辑 async getUsersCreatedAfter(time: Date) { return this.createQueryBuilder('user') .where('user.createdAt > :time', { time }) .getMany(); } }
该方案的模块注册、服务注入逻辑和方案1完全一致,不需要额外调整。
两种方案都完全遵循NestJS依赖注入规范,所有数据库操作逻辑都可以收敛到仓储层维护,不需要侵入服务层。
内容的提问来源于stack exchange,提问作者Andrii Abramov
相关产品推荐
相关产品推荐

