
本文详细介绍了如何在nest.js中使用`class-validator`创建自定义异步验证器,并解决在其中注入typeorm仓库时遇到的`null`引用问题。核心在于通过`@injectable()`装饰器将验证器纳入nest.js的依赖注入体系,并在相关模块中正确配置`typeormmodule.forfeature()`和将验证器注册为`provider`,从而确保仓库实例能够被正确注入并用于数据库操作。
在Nest.js应用开发中,数据验证是确保数据完整性和业务逻辑正确性的关键环节。class-validator库与Nest.js的集成提供了强大而灵活的验证能力,允许开发者定义各种复杂的验证规则,包括自定义异步验证。然而,当自定义验证器需要与数据库交互(例如检查某个字段的唯一性)时,正确地注入TypeORM仓库(Repository)常常成为一个挑战。本文将深入探讨如何解决在自定义class-validator约束中TypeORM仓库为null的问题,并提供一套完整的解决方案。
考虑一个常见的场景:我们需要验证一个实体(例如Parking)的名称在数据库中是否唯一。为此,我们可以创建一个自定义的class-validator装饰器和约束。最初的尝试可能如下所示:
// src/validators/unique-name.constraint.ts
import { InjectRepository } from '@nestjs/typeorm';
import {
  registerDecorator,
  ValidationOptions,
  ValidatorConstraint,
  ValidatorConstraintInterface,
  ValidationArguments,
} from 'class-validator';
import { Repository } from 'typeorm';
import { Parking } from '../entities/parking.entity'; // 假设这是您的实体
@ValidatorConstraint({ async: true })
export class UniqueNameConstraint implements ValidatorConstraintInterface {
  constructor(
    @InjectRepository(Parking) private parkingRepository: Repository<Parking>,
  ) {}
  async validate(name: any, args: ValidationArguments) {
    // 问题:这里的 this.parkingRepository 总是 null
    const parking = await this.parkingRepository.findOne({ where: { name } });
    return !parking; // 如果未找到,则名称唯一
  }
  defaultMessage(args: ValidationArguments) {
    return 'The name already exists';
  }
}
export function UniqueName(validationOptions?: ValidationOptions) {
  return function (object: object, propertyName: string) {
    registerDecorator({
      target: object.constructor,
      propertyName: propertyName,
      options: validationOptions,
      constraints: [],
      validator: UniqueNameConstraint,
    });
  };
}并在DTO中使用它:
// src/dto/create-entity.input.ts
import { Field, InputType } from '@nestjs/graphql'; // 假设使用GraphQL
import { UniqueName } from '../validators/unique-name.constraint';
@InputType()
export class CreateEntityInput {
  @UniqueName({ message: 'The name already exists' })
  @Field(() => String, { description: 'Name of the entity' })
  name: string;
}当运行上述代码时,UniqueNameConstraint中的this.parkingRepository会是null,导致数据库查询失败。这是因为class-validator在实例化UniqueNameConstraint时,并没有通过Nest.js的依赖注入(DI)容器来完成,因此@InjectRepository装饰器无法发挥作用。Nest.js的DI容器负责解析和提供所有被其管理的类的依赖。
要解决这个问题,我们需要确保UniqueNameConstraint也被Nest.js的DI容器所管理。这需要三个关键步骤:
使用@Injectable()装饰器标记UniqueNameConstraint类。这告诉Nest.js这个类可以被DI容器管理和实例化。
// src/validators/unique-name.constraint.ts
import { Injectable } from '@nestjs/common'; // 导入 Injectable
import { InjectRepository } from '@nestjs/typeorm';
import {
  registerDecorator,
  ValidationOptions,
  ValidatorConstraint,
  ValidatorConstraintInterface,
  ValidationArguments,
} from 'class-validator';
import { Repository } from 'typeorm';
import { Parking } from '../entities/parking.entity';
@Injectable() // <--- 添加此行
@ValidatorConstraint({ async: true })
export class UniqueNameConstraint implements ValidatorConstraintInterface {
  constructor(
    @InjectRepository(Parking) private parkingRepository: Repository<Parking>,
  ) {}
  async validate(name: any, args: ValidationArguments) {
    const parking = await this.parkingRepository.findOne({ where: { name } });
    return !parking;
  }
  defaultMessage(args: ValidationArguments) {
    return 'The name already exists';
  }
}
// ... UniqueName 装饰器保持不变 ...为了让@InjectRepository(Parking)能够找到并注入Parking实体的仓库,你需要在相关的Nest.js模块中注册该实体。这通常通过TypeOrmModule.forFeature()方法完成。
假设你的Parking实体在ParkingModule中使用,那么ParkingModule的imports数组应包含:
// src/parking/parking.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Parking } from './entities/parking.entity'; // 导入您的实体
// ... 其他导入
@Module({
  imports: [
    TypeOrmModule.forFeature([Parking]), // <--- 注册 Parking 实体仓库
    // ... 其他模块
  ],
  // ...
})
export class ParkingModule {}如果你的自定义验证器在其他模块中使用,或者你的应用结构比较简单,你也可以在AppModule中注册。关键是确保在验证器被实例化之前,Parking实体的仓库已经通过forFeature注册。
最后,你需要将UniqueNameConstraint类添加到Nest.js模块的providers数组中。这告诉Nest.js,UniqueNameConstraint是一个可被注入的服务,DI容器应该管理它的生命周期并解析其依赖。
// src/parking/parking.module.ts 或其他相关模块
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Parking } from './entities/parking.entity';
import { UniqueNameConstraint } from '../validators/unique-name.constraint'; // 导入您的验证器
@Module({
  imports: [
    TypeOrmModule.forFeature([Parking]),
  ],
  providers: [
    UniqueNameConstraint, // <--- 将验证器添加到 providers 数组
    // ... 其他服务
  ],
  exports: [
    // 如果其他模块需要使用 ParkingModule 提供的服务,可以导出
  ]
})
export class ParkingModule {}注意事项:
通过以上三个步骤,UniqueNameConstraint现在已经被Nest.js的DI容器管理。当class-validator需要实例化UniqueNameConstraint时,Nest.js将负责提供一个带有正确注入的parkingRepository实例的验证器。
// src/parking/parking.module.ts (示例)
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Parking } from './entities/parking.entity';
import { UniqueNameConstraint } from '../validators/unique-name.constraint'; // 确保路径正确
@Module({
  imports: [
    TypeOrmModule.forFeature([Parking]), // 注册实体仓库
  ],
  providers: [
    UniqueNameConstraint, // 注册自定义验证器为 provider
    // 其他与停车相关的服务...
  ],
  // 如果需要,可以导出 providers
  exports: [UniqueNameConstraint]
})
export class ParkingModule {}现在,你的自定义验证器应该能够正确地访问TypeORM仓库并执行数据库查询,从而实现复杂的异步验证逻辑。
总结:
在Nest.js中创建带有数据库交互的自定义class-validator约束时,核心在于理解Nest.js的依赖注入机制。确保以下三点:
遵循这些步骤,你将能够构建出健壮且功能强大的自定义验证逻辑,有效提升Nest.js应用的可靠性。
以上就是正确在Nest.js自定义验证器中注入TypeORM仓库的详细内容,更多请关注php中文网其它相关文章!
 
                        
                        每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
 
                 
                                
                                 收藏
收藏
                                                                             
                                
                                 收藏
收藏
                                                                             
                                
                                 收藏
收藏
                                                                            Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号