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

如何在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 23:45:19