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

NestJS+TypeORM关联PostgreSQL视图报错,求解决方案

解决TypeORM视图实体关联报错:Relation UsersView.profiles does not have join columns

问题场景

在NestJS中使用TypeORM关联PostgreSQL的两个视图实体view_users和view_profiles时,执行关联查询出现以下错误:

Relation UsersView.profiles does not have join columns.

期望实现类似普通表的关联查询,得到包含用户关联资料的嵌套结构。

错误原因

在UsersView实体的@OneToMany关联上错误添加了@JoinColumn装饰器。TypeORM的关联规则中:

  • @OneToMany关联的主实体(UsersView)不需要@JoinColumn,关联关系由反向的@ManyToOne实体(ProfilesView)通过外键维护
  • @JoinColumn仅需在@ManyToOne的一方使用,用来指定外键列(这里是ProfilesView的userId)

修正后的代码

UsersView 实体(修正后)

移除@OneToMany上的@JoinColumn装饰器:

import { OneToMany, ViewColumn, ViewEntity } from 'typeorm';
import { ProfilesView } from 'src/modules/profiles/entity/profiles.entity';

@ViewEntity({
    name: 'view_users',
    expression: `SELECT * FROM users`,
})
export class UsersView {
    @ViewColumn() id: number;
    @ViewColumn() userName: string;
    @ViewColumn() email: string;
    @ViewColumn() phoneNumber: string;
    @ViewColumn() createdAt: Date;
    @ViewColumn() updatedAt: Date;
    @ViewColumn() phoneCountryCode: string;
    @ViewColumn() deletedAt: Date;
    @ViewColumn() isBlacklist: boolean;
    @ViewColumn() fcmNotificationId: string;

    // 仅保留@OneToMany和反向关联字段,移除@JoinColumn
    @OneToMany(() => ProfilesView, (profiles) => profiles.user)
    profiles: ProfilesView[];
}

ProfilesView 实体(无需修改)

现有代码的@ManyToOne关联配置正确,保持不变:

import { JoinColumn, ManyToOne, ViewColumn, ViewEntity } from 'typeorm';
import { UsersView } from 'src/modules/users/entity/users.entity';

@ViewEntity({
    name: 'view_profiles',
    expression: `SELECT * FROM profile`,
})
export class ProfilesView {
    @ViewColumn() id: number;
    @ViewColumn() name: string;
    @ViewColumn() gender: string;
    @ViewColumn() phoneNumber: string;
    @ViewColumn() phoneCountryCode: string;
    @ViewColumn() email: string;
    @ViewColumn() identityCardNumber: string;
    @ViewColumn() isPatient: number;
    @ViewColumn() birthDate: Date;
    @ViewColumn() userId: number;
    @ViewColumn() unlocked: number;
    @ViewColumn() linked: number;
    @ViewColumn() createdAt: Date;
    @ViewColumn() updatedAt: Date;
    @ViewColumn() bpjsCardNumber: string;
    @ViewColumn() hasBpjs: number;
    @ViewColumn() deletedAt: Date;

    @ManyToOne(() => UsersView, (user) => user.profiles)
    @JoinColumn({ name: 'userId' })
    user: UsersView;
}

适配期望结果的字段名(可选)

如果需要返回结果中的字段名为profile(而非profiles),需同步修改两个实体的关联字段名:

  • UsersView中修改关联字段:
    @OneToMany(() => ProfilesView, (profiles) => profiles.user)
    profile: ProfilesView[];
    
  • ProfilesView中修改反向关联指向:
    @ManyToOne(() => UsersView, (user) => user.profile)
    @JoinColumn({ name: 'userId' })
    user: UsersView;
    

验证结果

修改完成后,调用UsersService的getData方法,即可得到符合期望的嵌套关联结果:

[
    {
        "id": 1,
        "phoneNumber": "xxxx", 
        "profile": [
            {
                "id": 1,
                "name": "xxx"
            }, 
            {
                "id": 2,
                "name": "xxx"
            }
        ]
    }
]

内容的提问来源于stack exchange,提问作者Robby Izhar Ramadhana

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 12:04:59