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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 12:25:22