NestJS中ClassValidator结合泛型实体实现DB存在性校验问题
解决NestJS自定义校验装饰器中@InjectRepository无法使用泛型的问题
问题根源
TypeScript的泛型是编译时类型,运行时会被类型擦除,所以你在ExistsValidation<T>中使用@InjectRepository(T)时,NestJS无法获取到实际的实体类(EntityClassOrSchema),自然无法注入对应的Repository。
解决方案思路
放弃在校验类中使用泛型,改为:
- 在自定义装饰器中直接传入实体类和要校验的列名,将二者作为校验约束传递
- 校验类注入
EntityManager,通过实体类动态获取对应的Repository,执行查询校验
修改后的完整代码
1. 自定义装饰器 Exists
import { registerDecorator, ValidationOptions, ValidationArguments } from 'class-validator'; import { EntityClassOrSchema } from '@nestjs/typeorm'; export function Exists(entity: EntityClassOrSchema, columnName: string, validationOptions?: ValidationOptions) { return function (object: Object, propertyName: string) { registerDecorator({ target: object.constructor, propertyName: propertyName, constraints: [entity, columnName], // 将实体类和列名存入约束 options: validationOptions, validator: ExistsValidation, }); }; }
2. 校验类 ExistsValidation
import { ValidatorConstraint, ValidatorConstraintInterface, ValidationArguments } from 'class-validator'; import { Injectable } from '@nestjs/common'; import { EntityManager, Repository } from 'typeorm'; @ValidatorConstraint({ name: 'Exists', async: true }) @Injectable() export class ExistsValidation implements ValidatorConstraintInterface { constructor(private readonly entityManager: EntityManager) {} async validate(value: any, args: ValidationArguments): Promise<boolean> { // 从约束中取出实体类和列名 const [entity, columnName] = args.constraints; // 通过EntityManager获取对应实体的Repository const repository: Repository<any> = this.entityManager.getRepository(entity); // 查询是否存在匹配记录 const exists = await repository.exists({ where: { [columnName]: value } }); return exists; } }
3. DTO 使用示例
import { IsNotEmpty, IsEmail } from 'class-validator'; import Users from '../entities/users.entity'; // 导入你的Users实体类 import { Exists } from '../decorators/exists.decorator'; export default class MyDto { @IsNotEmpty({ message: 'Email is required' }) @IsEmail({}, { message: 'Email must be a valid email' }) // 传入实体类和要校验的列名(这里应该是email列,你之前写的id是笔误吧?) @Exists(Users, 'email', { message: 'Email does not exist in system' }) email: string; }
额外注意
- 确保你的实体类已经在NestJS模块中通过
TypeOrmModule.forFeature([Users])注册 - 校验类
ExistsValidation需要在你的模块中注册为提供者(providers),同时要确保class-validator和class-transformer的配置正确
内容的提问来源于stack exchange,提问作者Maaz Khan
相关产品推荐
相关产品推荐

