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
相关产品推荐
相关产品推荐

