TypeORM:如何实现双向关系,多字段 --> 一种实体类型

bak*_*aku 8 erd one-to-many typeorm

我创建了一个“文档”实体:

例如

@Entity()
export class Document {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name: string;

  @Column()
  path: string;
   ...

}
Run Code Online (Sandbox Code Playgroud)

多个文档可以与不同的实体类型相关:post、userProfile 等

例如,在帖子实体中,我有几个字段都指定了文档关系。

  @OneToOne(type => DocumentEntity)
  @JoinColumn({ name: 'default_document' })
  defaultDocument: DocumentEntity;

  @OneToOne(type => DocumentEntity)
  @JoinColumn({ name: 'featured_document' })
  featuredDocument: DocumentEntity;

  @OneToMany(type => DocumentEntity, document => document.post)
  @JoinColumn({ name: 'other_documents' })
  otherDocs: DocumentEntity[]; 
Run Code Online (Sandbox Code Playgroud)

我不清楚如何使文档关系双向。我曾希望在文档上有一个字段,例如:

  @ManyToOne(type => abstractEntity, entity => entity.document)
  parentEntity: abstractEntity;
Run Code Online (Sandbox Code Playgroud)

这样,如果我查询文档实体的父关系,我会得到如下结果:

documents: [
{
id: 1,
name: 'document 1', 
path: 'https://image.hosted.service/1.jpg', 
parentEntityId: 23
}, 
{
id: 2
name: 'document 2', 
path: 'https://image.hosted.service/2.jpg'
parentEntityId: 27
}
] 
Run Code Online (Sandbox Code Playgroud)

但是 Typeorm 似乎希望我为 documentEntity 上的每个父关系字段定义一个完全匹配的字段,例如:

@Entity()
export class Document {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name: string;

  @Column()
  path: string;
  ...

  @OneToOne(type => PostEntity, post => post.defaultDocument)
  postEntityDefaultDoc: PostEntity;

  @OneToOne(type => PostEntity, post => post.featuredDocument)
  postEntityFeaturedDoc: PostEntity;

  @ManyToOne(type => PostEntity, post => post.otherDocs)
  otherDocs: PostEntity[];


}
Run Code Online (Sandbox Code Playgroud)

在这个例子中为了简单起见,没有 M:N 关系:文档最多可以有一个父级。

对于父实体字段引用文档的每个可能实例,我必须在文档实体上定义一个新字段似乎不正确。对文档的查询不会返回一个包含一个定义父实体的字段的列表,而是我必须解析/聚合任意数量的字段。

我似乎找不到任何教程/示例,其中单个实体有许多字段,每个字段都引用同一个其他实体,这让我认为我的基本方法有缺陷。

小智 1

秘密成分是leftJoinAndMapMany它允许您加入任意实体并将其映射到属性。

这就是我在你的情况下会做的事情。看起来DocumentEntity像这样:

@Entity()
class DocumentEntity {
    @PrimaryGeneratedColumn()
    public id!: number;

    @Column()
    public entity!: string;

    @Column({
        name: 'entity_id',
    })
    public entityId!: string;

    @Column()
    public name!: string;
}
Run Code Online (Sandbox Code Playgroud)

你的PostEntity看起来像这样:

@Entity()
class PostEntity {
    @PrimaryGeneratedColumn()
    public id!: number;

    @Column()
    public name: string;

    public documents?: DocumentEntity[];
}
Run Code Online (Sandbox Code Playgroud)

您可能会注意到,帖子上的文档没有注释。那是因为我们将使用上述方法进行连接。你的查询看起来像这样:

connection
    .getRepository(PostEntity)
    .createQueryBuilder('p')
    .leftJoinAndMapMany(
        'p.documents',
        DocumentEntity,
        'p__d',
        '(p.id = md.entityId AND md.entity = :documentEntity)',
        {
            documentEntity: PostEntity.name,
        },
    )
    .getMany()
Run Code Online (Sandbox Code Playgroud)

这些方法可用于加入这些实体:

  • leftJoinAndMapMany
  • innerJoinAndMapMany
  • leftJoinAndMapOne
  • innerJoinAndMapOne