Typeorm getMany()未返回左连非关联实体问题排查
TypeORM getMany() 未返回非关联实体数据的问题解决
我在使用TypeORM的getMany()时遇到问题,执行以下代码仅返回Results实体,没有包含UserAnag的数据:
const res = await this.repo .createQueryBuilder('result') .leftJoinAndSelect( UserAnag, 'useranag', 'useranag.playerId = result.playerId', ) .where('result.server = :idServer', { idServer: serverId }) .andWhere('result.raceId = :idRace', { idRace: raceId }) .getMany();
改用getRawMany()可以拿到所有数据,但返回的是原始扁平化结构:
result.id, result.position, useranag.id, useranag.name
我期望getMany()返回嵌套结构:
result.id, result.position, useranag: { id: xx, name: yyy }
UserAnag和Results通过playerId关联,但实体中没有定义正式的关联关系。TypeORM文档提到可以对非关联实体使用leftJoinAndSelect配合getMany(),但实际没达到预期效果。
实体定义如下:
Results 实体
@Entity() export class Results { @PrimaryGeneratedColumn() id: number; @Column() position: number; @Column() laps: number; @Column({ type: 'time', precision: 3 }) bestLaps: Date; @Column({ type: 'time', precision: 3 }) gap: Date; @Column() penalties: number; @Column() server: number; @Column() playerId: string; @ManyToOne(() => Cars, (cars) => cars.result) car: Cars; @ManyToOne( () => Competitionraces, (competitionRaces) => competitionRaces.result, ) race: Competitionraces; }
UserAnag 实体
@Entity() export class UserAnag { @PrimaryGeneratedColumn() id: number; @Column() name: string; @Column() surname: string; @Column() psn: string; @Column() discord: string; @Column() drivernumber: number; @Column() playerId: number; @OneToOne(() => User, (user) => user.useranag, { onDelete: 'CASCADE', }) @JoinColumn() user: User; @ManyToOne(() => Discord, (useranag) => useranag.siglaTeam) discordTeam: Discord; }
问题本质
getMany()的工作逻辑依赖实体的元数据,它只会将查询结果填充到实体类已定义的属性中。你的Results实体里没有useranag属性,即使leftJoinAndSelect查询到了UserAnag的数据,getMany()也无法识别该把数据挂载到哪里,因此只会返回Results本身的字段。而getRawMany()是直接返回数据库的原始查询行,所以能看到所有关联字段。
解决方案
方案1:在实体中定义正式关联(推荐)
既然两个实体通过playerId关联,直接在Results中添加关联映射,让TypeORM自动处理数据嵌套:
- 修改
Results实体,添加UserAnag的关联(注意统一playerId的类型:当前Results的playerId是string,UserAnag的是number,需要先统一类型,比如都改成string或number):
@Entity() export class Results { // 保留原有所有字段... @Column() playerId: string; // 确保和UserAnag的playerId类型一致 // 添加关联映射,手动指定关联字段(因为不是默认的外键名) @ManyToOne(() => UserAnag) @JoinColumn({ name: 'playerId', referencedColumnName: 'playerId' }) useranag: UserAnag; }
- (可选)如果需要反向关联,在
UserAnag中添加:
@Entity() export class UserAnag { // 保留原有所有字段... @OneToMany(() => Results, result => result.useranag) results: Results[]; }
修改后,原来的getMany()代码就能直接返回包含useranag嵌套对象的Results实体了。
方案2:手动转换原始数据(不修改实体)
如果不想修改实体结构,可以用getRawMany()获取数据后手动映射成期望的嵌套结构:
const res = await this.repo .createQueryBuilder('result') .leftJoin( UserAnag, 'useranag', 'useranag.playerId = result.playerId', ) .select([ 'result.id AS result_id', 'result.position AS result_position', 'useranag.id AS useranag_id', 'useranag.name AS useranag_name', ]) .where('result.server = :idServer', { idServer: serverId }) .andWhere('result.raceId = :idRace', { idRace: raceId }) .getRawMany() .then(rawList => rawList.map(item => ({ id: item.result_id, position: item.result_position, useranag: { id: item.useranag_id, name: item.useranag_name // 按需添加其他UserAnag字段 } })));
或者使用QueryBuilder的setTransformer来处理转换:
const res = await this.repo .createQueryBuilder('result') .leftJoinAndSelect( UserAnag, 'useranag', 'useranag.playerId = result.playerId', ) .where('result.server = :idServer', { idServer: serverId }) .andWhere('result.raceId = :idRace', { idRace: raceId }) .setTransformer(rawItem => { // 提取useranag字段并嵌套 const transformed = { id: rawItem.result_id, position: rawItem.result_position, // 保留Results的其他字段... useranag: { id: rawItem.useranag_id, name: rawItem.useranag_name } }; // 删除扁平化的前缀字段(可选) Object.keys(rawItem).forEach(key => { if (key.startsWith('useranag_')) delete transformed[key]; }); return transformed; }) .getRawMany();
内容的提问来源于stack exchange,提问作者Massimiliano Oreto
相关产品推荐
相关产品推荐

