You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NestJS中ClassValidator结合泛型实体实现DB存在性校验问题

解决NestJS自定义校验装饰器中@InjectRepository无法使用泛型的问题

问题根源

TypeScript的泛型是编译时类型,运行时会被类型擦除,所以你在ExistsValidation<T>中使用@InjectRepository(T)时,NestJS无法获取到实际的实体类(EntityClassOrSchema),自然无法注入对应的Repository。

解决方案思路

放弃在校验类中使用泛型,改为:

  1. 在自定义装饰器中直接传入实体类和要校验的列名,将二者作为校验约束传递
  2. 校验类注入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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 09:07:38