升级TypeORM 0.3.12后NestJS自定义Repository方法调用失败
NestJS升级TypeORM 0.3.12后E2E测试报错的解决方法
问题背景
- 已完成NestJS项目到TypeORM 0.3.12的升级,所有集成测试(如
TypeOrmAthleteRepository相关测试)已修复并可正常通过 - 运行E2E测试时触发两个关键错误:
[ExceptionHandler] this.athleteRepository.findByEmail is not a functionEntityMetadataNotFoundError: No metadata for "TypeOrmAthleteRepository" was found
排查与解决方法
1. 自定义仓库注入逻辑错误
TypeORM 0.3.x对自定义仓库的注入规则有调整,E2E测试中可能误将仓库类当作实体注入,而非通过正确方式获取实例。
修正步骤:
- 服务类中确保用
@InjectRepository()正确注入自定义仓库:import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { TypeOrmAthleteRepository } from './typeorm-athlete.repository'; @Injectable() export class AthleteService { constructor( @InjectRepository(TypeOrmAthleteRepository) private readonly athleteRepository: TypeOrmAthleteRepository, ) {} async findByEmail(email: string) { return this.athleteRepository.findByEmail(email); } } - 自定义仓库需正确继承
Repository并关联实体:import { Repository } from 'typeorm'; import { Athlete } from './athlete.entity'; // TypeORM 0.3.x已废弃@EntityRepository,直接继承Repository即可 export class TypeOrmAthleteRepository extends Repository<Athlete> { async findByEmail(email: string) { return this.findOne({ where: { email } }); } }
2. AppModule配置错误
检查AppModule的TypeORM配置,确认实体路径正确,且自定义仓库已正确注册。
正确配置示例:
import { Module } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { Athlete } from './athlete.entity'; import { TypeOrmAthleteRepository } from './typeorm-athlete.repository'; import { AthleteService } from './athlete.service'; @Module({ imports: [ TypeOrmModule.forRoot({ type: 'postgres', host: 'localhost', port: 5432, username: 'postgres', password: 'password', database: 'test', entities: [Athlete], // 这里只注册实体,不要注册仓库类 synchronize: true, }), TypeOrmModule.forFeature([Athlete, TypeOrmAthleteRepository]), // 同时注册实体和自定义仓库 ], providers: [AthleteService], exports: [AthleteService], }) export class AppModule {}
3. E2E测试模块配置遗漏
E2E测试模块可能未正确导入TypeORM配置或自定义仓库,导致依赖注入失败。
测试模块修正示例:
import { Test, TestingModule } from '@nestjs/testing'; import { INestApplication } from '@nestjs/common'; import { TypeOrmModule } from '@nestjs/typeorm'; import { AthleteService } from '../src/athlete.service'; import { TypeOrmAthleteRepository } from '../src/typeorm-athlete.repository'; import { Athlete } from '../src/athlete.entity'; describe('Athlete E2E', () => { let app: INestApplication; let athleteService: AthleteService; beforeEach(async () => { const moduleFixture: TestingModule = await Test.createTestingModule({ imports: [ TypeOrmModule.forRoot({ type: 'postgres', host: 'localhost', port: 5432, username: 'postgres', password: 'password', database: 'test_e2e', entities: [Athlete], synchronize: true, dropSchema: true, // 测试前清空数据库 }), TypeOrmModule.forFeature([TypeOrmAthleteRepository]), ], providers: [AthleteService], }).compile(); app = moduleFixture.createNestApplication(); await app.init(); athleteService = moduleFixture.get<AthleteService>(AthleteService); }); afterEach(async () => { await app.close(); }); it('should find athlete by email', async () => { const email = 'test@example.com'; const result = await athleteService.findByEmail(email); expect(result).toBeDefined(); }); });
4. 适配@EntityRepository废弃规则
TypeORM 0.3.x已彻底废弃@EntityRepository装饰器,若旧代码使用了该装饰器,需替换为手动继承Repository的方式:
旧代码(需替换):
import { EntityRepository, Repository } from 'typeorm'; import { Athlete } from './athlete.entity'; @EntityRepository(Athlete) export class TypeOrmAthleteRepository extends Repository<Athlete> { // ...自定义方法 }
新代码:
import { Repository, DataSource } from 'typeorm'; import { Athlete } from './athlete.entity'; export class TypeOrmAthleteRepository extends Repository<Athlete> { constructor(dataSource: DataSource) { super(Athlete, dataSource.createEntityManager()); } // ...自定义方法 }
同时在模块中仅注册实体,仓库实例可通过DataSource手动生成或依赖注入获取。
内容的提问来源于stack exchange,提问作者A Mehmeto
相关产品推荐
相关产品推荐

