如何在TypeORM中创建带静态值的关联列?多态关联实现
解决TypeORM中自定义多态关联列的问题
针对你遇到的TypeORM不支持@JoinColumn设置静态值的问题,这里有几个可行的解决方案:
方案一:手动维护多态字段 + 生命周期钩子自动赋值
显式定义record_id和record_type字段,通过生命周期钩子在保存/更新时自动设置对应实体的类型值,查询时同时过滤关联ID和类型:
@Entity({ name: 'attachments' }) export class Attachment { @PrimaryGeneratedColumn() id: number; // 显式声明多态关联字段 @Column() record_id: number; @Column() record_type: string; // 仅通过record_id关联父实体 @ManyToOne(() => Advertisement, (advertisement) => advertisement.attachments) @JoinColumn({ name: 'record_id', referencedColumnName: 'id' }) advertisement: Advertisement; @ManyToOne(() => Blog, (blog) => blog.attachments) @JoinColumn({ name: 'record_id', referencedColumnName: 'id' }) blog: Blog; // 钩子函数:根据当前关联的实体自动设置record_type @BeforeInsert() @BeforeUpdate() setRecordType() { if (this.advertisement) { this.record_type = 'Advertisement'; } else if (this.blog) { this.record_type = 'Blog'; } } }
查询时需要同时指定关联ID和类型,避免跨实体匹配:
// 查询某广告的附件 const adAttachments = await attachmentRepository.find({ where: { advertisement: adId, record_type: 'Advertisement' } });
方案二:使用TypeORM原生多态关联(推荐)
TypeORM原生支持多态关联,可以直接自定义列名,无需手动维护类型值:
@Entity({ name: 'attachments' }) export class Attachment { @PrimaryGeneratedColumn() id: number; // 自定义多态列名,自动处理record_id和record_type @PolymorphicColumn({ idColumn: 'record_id', typeColumn: 'record_type' }) record: Advertisement | Blog; }
父实体中定义反向关联:
// Advertisement实体 @Entity() export class Advertisement { @PrimaryGeneratedColumn() id: number; @OneToMany(() => Attachment, (attachment) => attachment.record) attachments: Attachment[]; } // Blog实体同理 @Entity() export class Blog { @PrimaryGeneratedColumn() id: number; @OneToMany(() => Attachment, (attachment) => attachment.record) attachments: Attachment[]; }
使用时直接通过record关联即可,TypeORM会自动处理record_type的值:
// 查询某博客的附件 const blogAttachments = await attachmentRepository.find({ where: { record: blogId } });
方案三:完全通过QueryBuilder手动处理
如果需要完全自定义逻辑,可以绕过实体关联装饰器,用QueryBuilder直接操作:
保存附件
// 保存属于Blog的附件 await attachmentRepository .createQueryBuilder() .insert() .into(Attachment) .values({ // 其他字段 record_id: blogId, record_type: 'Blog' }) .execute();
查询附件
// 查询某广告的附件并关联广告信息 const adAttachments = await attachmentRepository .createQueryBuilder('attachment') .leftJoinAndSelect('attachment.advertisement', 'advertisement') .where('attachment.record_id = :adId', { adId }) .andWhere('attachment.record_type = :type', { type: 'Advertisement' }) .getMany();
内容的提问来源于stack exchange,提问作者OULAHTAK
相关产品推荐
相关产品推荐

