NestJS+GraphQL+TypeORM如何将懒加载关联Promise转为数组模型?
问题描述
我正在使用NestJS搭配GraphQL(Apollo)和TypeORM,实体中的roles是懒加载关联,类型为Promise<UserRolesEntity[]>,但GraphQL的UserModel里roles被定义为UserRolesModel[],导致TypeScript报错,无法自动将Promise数组转换为普通数组。
UserModel 代码
@ObjectType({ description: 'User' }) export class UserModel { @Field() id: string; @Field(() => [UserRolesModel], { nullable: true }) roles?: UserRolesModel[] }
UserEntity 代码
@Entity({ name: 'user' }) export class UserEntity { @PrimaryGeneratedColumn('uuid') id: string; @OneToMany(() => UserRolesEntity, (userRoles) => userRoles.userId) roles: Promise<UserRolesEntity[]>; }
TypeScript 报错信息
TS2322: Type 'UserEntity[]' is not assignable to type 'UserModel[]'. Type 'UserEntity' is not assignable to type 'UserModel'. Types of property 'roles' are incompatible. Type 'Promise<UserRolesEntity[]>' is missing the following properties from type 'UserRolesModel[]': length, pop, push, concat, and 29 more.
解决方法
1. 手动解析Promise并转换实体到模型
在服务层获取UserEntity后,先通过await解析懒加载的roles拿到实际数组,再用class-transformer完成实体到模型的转换:
import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { UserEntity } from './user.entity'; import { UserModel } from './user.model'; import { plainToInstance } from 'class-transformer'; import { UserRolesModel } from './user-roles.model'; @Injectable() export class UserService { constructor( @InjectRepository(UserEntity) private userRepo: Repository<UserEntity>, ) {} async getUser(id: string): Promise<UserModel> { const userEntity = await this.userRepo.findOne({ where: { id } }); // 手动解析懒加载的roles const resolvedRoles = await userEntity.roles; // 转换UserEntity到UserModel const userModel = plainToInstance(UserModel, userEntity); // 单独转换roles并赋值 userModel.roles = plainToInstance(UserRolesModel, resolvedRoles); return userModel; } }
2. 自定义class-transformer转换器
创建一个自定义转换器,自动处理Promise类型的属性,避免手动解析:
import { Transform } from 'class-transformer'; // 自定义转换器:处理Promise数组类型的转换 export const TransformPromiseArray = () => Transform(async ({ value }) => { if (value instanceof Promise) { const resolvedValue = await value; return resolvedValue; } return value; }, { toClassOnly: true });
在UserModel中引入该转换器:
@ObjectType({ description: 'User' }) export class UserModel { @Field() id: string; @Field(() => [UserRolesModel], { nullable: true }) @TransformPromiseArray() roles?: UserRolesModel[] }
转换时需要开启class-transformer的异步转换支持:
const userModel = await plainToInstance(UserModel, userEntity, { enableCircularCheck: true, asyncTransformations: true, });
3. 关闭懒加载(业务允许时)
如果业务场景不需要懒加载,可以修改UserEntity的关联定义,直接返回数组类型:
@Entity({ name: 'user' }) export class UserEntity { @PrimaryGeneratedColumn('uuid') id: string; @OneToMany(() => UserRolesEntity, (userRoles) => userRoles.userId, { lazy: false }) roles: UserRolesEntity[]; }
查询时需要手动关联加载roles:
const userEntity = await this.userRepo.findOne({ where: { id }, relations: ['roles'], });
之后直接用class-transformer转换即可:
const userModel = plainToInstance(UserModel, userEntity);
内容的提问来源于stack exchange,提问作者ptheofan
相关产品推荐
相关产品推荐

