如何在NestJS中动态注入Repository,实现接收实体创建仓库的服务
NestJS中动态注入Repository的正确实现方式
原代码的问题分析
- 手动实例化服务(
new MyService(MyEntity))绕过了Nest的依赖注入(DI)系统,InjectRepository装饰器依赖DI容器才能解析Repository实例,直接调用无法生效。 - 构造参数类型错误:
entity应该传入**实体类(typeof T)**而非实体实例(T)。 InjectRepository的用法错误:它是用来修饰构造参数的装饰器,不能手动调用它为类属性赋值。
正确实现方案
方案一:通过Injector动态获取Repository
利用Nest的Injector服务,在运行时根据传入的实体类获取对应的Repository实例,适合需要灵活切换实体的场景。
import { Injectable, Injector } from '@nestjs/common'; import { Repository, ObjectLiteral, getRepositoryToken } from 'typeorm'; @Injectable() export class MyService<T extends ObjectLiteral> { private repo: Repository<T> | null = null; constructor(private readonly injector: Injector) {} // 设置要操作的实体类,并初始化Repository setEntity(entity: typeof T): void { const repoToken = getRepositoryToken(entity); this.repo = this.injector.get<Repository<T>>(repoToken); } // 示例CRUD方法 async findAll(): Promise<T[]> { if (!this.repo) { throw new Error('请先调用setEntity设置目标实体'); } return this.repo.find(); } async findOne(id: number): Promise<T | null> { if (!this.repo) { throw new Error('请先调用setEntity设置目标实体'); } return this.repo.findOneBy({ id } as any); } }
使用方式
在其他服务中注入MyService,调用setEntity绑定实体后即可使用:
import { Injectable } from '@nestjs/common'; import { MyService } from './my.service'; import { UserEntity } from './user.entity'; @Injectable() export class UserService { constructor(private readonly myService: MyService<UserEntity>) { // 绑定UserEntity this.myService.setEntity(UserEntity); } async getUsers() { return this.myService.findAll(); } }
方案二:工厂Provider创建实体专用服务
如果需要为特定实体创建专用的服务实例,可以通过工厂函数动态生成Provider,确保Repository被正确注入。
1. 定义工厂Provider
import { Provider } from '@nestjs/common'; import { Repository, ObjectLiteral, getRepositoryToken } from 'typeorm'; import { MyService } from './my.service'; // 生成针对特定实体的MyService Provider export const createEntityServiceProvider = <T extends ObjectLiteral>(entity: typeof T): Provider => ({ provide: `${entity.name}Service`, useFactory: (repo: Repository<T>) => { const service = new MyService<T>(); service.repo = repo; return service; }, inject: [getRepositoryToken(entity)], });
2. 在模块中注册
import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { createEntityServiceProvider } from './entity-service.provider'; import { UserEntity } from './user.entity'; import { PostEntity } from './post.entity'; @Module({ imports: [TypeOrmModule.forFeature([UserEntity, PostEntity])], providers: [ createEntityServiceProvider(UserEntity), createEntityServiceProvider(PostEntity), ], exports: [ createEntityServiceProvider(UserEntity), createEntityServiceProvider(PostEntity), ], }) export class EntityModule {}
3. 使用专用服务
import { Injectable, Inject } from '@nestjs/common'; import { MyService } from './my.service'; import { UserEntity } from './user.entity'; @Injectable() export class UserController { constructor( @Inject(`${UserEntity.name}Service`) private readonly userService: MyService<UserEntity>, ) {} async getUsers() { return this.userService.findAll(); } }
关键注意事项
- 确保目标实体已经通过
TypeOrmModule.forFeature([Entity])在模块中注册,否则DI容器无法找到对应的Repository。 - 泛型
T需要继承TypeORM的ObjectLiteral,确保符合实体类型要求。
内容的提问来源于stack exchange,提问作者Sherif eldeeb
相关产品推荐
相关产品推荐

