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

TypeORM私有实体属性多关系定义报错:getProperty不是函数

解决TypeORM中实体私有属性关联报错:entity.getProperty is not a function

问题场景

在Node.js应用中使用TypeORM定义实体间一对多/多对一关联时,将实体属性设为private,通过自定义的getProperty方法访问属性值。但启动时抛出错误:TypeError: user.getProperty is not a function,相关实体代码及错误栈如下:

User实体代码

@Entity()
class User {

    private USER_ID_PREFIX: string = "uid-";

    @PrimaryColumn()
    private id: string;
    @Column({nullable: false, length: 15})
    private firstname: string;
    @Column({nullable: false, length: 15})
    private lastname: string;
    @Column({nullable: false, unique: true, length: 25})
    private email: string;
    @Column({nullable: false})
    private password: string;
    @OneToMany(() => Role, (role) => role.getProperty(EntityProperty.USER))
    private roles: Role[];

    public constructor(...args: any[]) {
        if (args.length === 0)
            return;
        if (args.length === 1) {
            if (args[0] instanceof UserCreateRequestDto) {
                let requestDto = args[0];
                this.id = this.USER_ID_PREFIX + randomUUID();
                this.firstname = requestDto.getProperty(DtoProperty.FIRSTNAME);
                this.lastname = requestDto.getProperty(DtoProperty.LASTNAME);
                this.email = requestDto.getProperty(DtoProperty.EMAIL);
                this.password = requestDto.getProperty(DtoProperty.PASSWORD);
            }
        }
    }

    public getProperty(property: EntityProperty): any {
        if (property === EntityProperty.ID)
            return this.id;
        if (property === EntityProperty.FIRSTNAME)
            return this.firstname;
        if (property === EntityProperty.LASTNAME)
            return this.lastname;
        if (property === EntityProperty.EMAIL)
            return this.email;
        if (property === EntityProperty.PASSWORD)
            return this.password;
        if (property === EntityProperty.ROLES)
            return this.roles;
        throw new Error(`No such entity property as ${property.toString()} exists in User`);
    }
}

export default User;

Role实体代码

@Entity()
class Role {

    private ROLE_ID_PREFIX: string = "rid-";

    @PrimaryColumn()
    private id: string;
    @Column({nullable: false})
    private role: string;
    @ManyToOne(() => User, (user) => user.getProperty(EntityProperty.ROLES))
    private user: User;

    public constructor(...args: any[]) {
        if (args.length === 0)
            return;
        if (args.length === 1) {
            if (args[0] instanceof RoleCreateRequestDto) {
                let requestDto = args[0];
                this.id = this.ROLE_ID_PREFIX + randomUUID();
                this.role = requestDto.getProperty(DtoProperty.ROLE);
            }
        }
    }

    public getProperty(property: EntityProperty): any {
        if (property === EntityProperty.ID)
            return this.id;
        if (property === EntityProperty.ROLE)
            return this.role;
        if (property === EntityProperty.USER)
            return this.user;
        throw new Error(`No such entity property as ${property.toString()} exists in Role`);
    }
}

export default Role;

错误栈

query: SELECT VERSION() AS `version`
Error initializing mysql datasource TypeError: user.getProperty is not a function
    at RelationMetadata.givenInverseSidePropertyFactory (D:\Swivel_Projects\Ignite\Project 1\backend\ignite-auth-nodejs\src\entities\Role.ts:22:43)
    at RelationMetadata.buildInverseSidePropertyPath (D:\Swivel_Projects\Ignite\Project 1\backend\ignite-auth-nodejs\node_modules\src\metadata\RelationMetadata.ts:628:29)
    at D:\Swivel_Projects\Ignite\Project 1\backend\ignite-auth-nodejs\node_modules\src\metadata-builder\EntityMetadataBuilder.ts:1116:26
    at Array.forEach (<anonymous>)
    at EntityMetadataBuilder.computeInverseProperties (D:\Swivel_Projects\Ignite\Project 1\backend\ignite-auth-nodejs\node_modules\src\metadata-builder\EntityMetadataBuilder.ts:1096:34)
    at D:\Swivel_Projects\Ignite\Project 1\backend\ignite-auth-nodejs\node_modules\src\metadata-builder\EntityMetadataBuilder.ts:158:18
    at Array.forEach (<anonymous>)
    at EntityMetadataBuilder.build (D:\Swivel_Projects\Ignite\Project 1\backend\ignite-auth-nodejs\node_modules\src\metadata-builder\EntityMetadataBuilder.ts:157:25)
    at ConnectionMetadataBuilder.buildEntityMetadatas (D:\Swivel_Projects\Ignite\Project 1\backend\ignite-auth-nodejs\node_modules\src\connection\ConnectionMetadataBuilder.ts:106:11)
    at processTicksAndRejections (node:internal/process/task_queues:96:5)

错误原因

TypeORM在构建关联元数据阶段,传递给关联装饰器(@OneToMany/@ManyToOne)的回调函数参数并不是实体的实例对象,而是TypeORM内部用于解析属性的上下文对象,这个对象没有自定义的getProperty方法,因此调用该方法会抛出错误。

关联装饰器的回调函数要求直接返回实体的属性引用,而不是通过实例方法间接获取。

解决方案

修改关联装饰器的回调函数,直接引用实体的私有属性名,同时保留getProperty方法供业务逻辑使用:

修改后的User实体关联部分

@OneToMany(() => Role, (role) => role.user) // 直接引用role的user属性
private roles: Role[];

修改后的Role实体关联部分

@ManyToOne(() => User, (user) => user.roles) // 直接引用user的roles属性
private user: User;

说明

  • TypeORM在元数据解析阶段可以访问实体的私有属性,不需要将属性设为public
  • 业务代码中仍然可以通过getProperty方法安全访问实体属性,保持封装性

内容的提问来源于stack exchange,提问作者CleanCodeOnline

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 06:44:55