Mikro-ORM 如何通过BaseEntity实现多实体关联FileAttachment附件功能
你提出的两个需求在Mikro-ORM中都可以实现,更推荐使用多态关联方案匹配你优化后的FileAttachment结构,具体实现如下:
推荐方案:单多态字段关联
该方案仅需在FileAttachment中定义一个usedBy关联字段,即可支持所有继承自BaseEntity的实体关联附件,无需随关联实体新增修改FileAttachment结构。
1. 实体定义
首先定义抽象父类BaseEntity:
import { Entity, PrimaryKey, Property, OneToMany, BaseEntity as MikroBaseEntity } from '@mikro-orm/core' import { FileAttachment } from './file-attachment.entity' @Entity({ abstract: true }) export abstract class BaseEntity extends MikroBaseEntity<BaseEntity, 'id'> { @PrimaryKey() id: number // 统一附件关联,反向多态一对多 @OneToMany({ entity: () => FileAttachment, mappedBy: 'usedBy', polymorphic: true, orphanRemoval: true // 可选配置:主实体删除时自动删除关联的附件 }) files: FileAttachment[] = [] }
然后定义业务子实体,直接继承BaseEntity即可,无需重复定义附件关联:
@Entity() export class Book extends BaseEntity { // 自有属性示例 @Property() title: string } @Entity() export class Author extends BaseEntity { @Property() name: string } @Entity() export class Store extends BaseEntity { @Property() address: string }
最后定义FileAttachment实体:
import { Entity, PrimaryKey, Property, Any } from '@mikro-orm/core' import { Book } from './book.entity' import { Author } from './author.entity' import { Store } from './store.entity' @Entity() export class FileAttachment { @PrimaryKey() id: number @Property() fileName: string @Property() fileSize: number // 多态关联字段,可指向任意指定的实体 @Any({ type: 'int', // 和BaseEntity的主键类型保持一致 entity: () => [Book, Author, Store] // 允许关联的实体列表 }) usedBy: Book | Author | Store }
2. 使用示例
// 给Book新增附件 const book = em.create(Book, { title: '测试书籍' }) const cover = em.create(FileAttachment, { fileName: 'cover.jpg', fileSize: 10240, usedBy: book }) await em.persist(book).persist(cover).flush() // 读取实体关联的附件 const bookWithFiles = await em.findOne(Book, 1, { populate: ['files'] }) console.log(bookWithFiles.files) // 直接获取该书籍关联的所有附件
该方案的数据库FileAttachment表会自动生成usedBy_type、usedBy_id两个字段,分别存储关联的实体名称、实体主键,由Mikro-ORM自动维护,无需手动操作。
可选方案:多外键字段关联
如果你需要使用你提到的FileAttachment多关联字段的结构,也可以在BaseEntity中动态配置关联,无需每个子实体单独定义附件属性:
// BaseEntity中的files配置 @OneToMany({ entity: () => FileAttachment, // 动态匹配子实体对应的关联字段,如Book对应refToBook mappedBy: (entity) => `refTo${entity.constructor.name}`, orphanRemoval: true }) files: FileAttachment[] = []
FileAttachment实体定义:
@Entity() export class FileAttachment { @PrimaryKey() id: number @ManyToOne(() => Book, { nullable: true }) refToBook?: Book @ManyToOne(() => Author, { nullable: true }) refToAuthor?: Author @ManyToOne(() => Store, { nullable: true }) refToStore?: Store }
该方案缺点为每新增一个需要关联附件的实体,都需要在FileAttachment中新增对应的外键字段,扩展性较差。
内容的提问来源于stack exchange,提问作者gogo199432
相关产品推荐
相关产品推荐

