TypeORM:如何实现双向关系,多个字段 --> 一种实体类型
Posted
技术标签:
【中文标题】TypeORM:如何实现双向关系,多个字段 --> 一种实体类型【英文标题】:TypeORM: how to implement bidirectional relationship, multiple fields --> one entity type 【发布时间】:2019-11-07 17:32:46 【问题描述】:我创建了一个“文档”实体:
例如
@Entity()
export class Document
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@Column()
path: string;
...
多个文档可以关联不同的实体类型:post、userProfile等
例如,在 post 实体中,我有几个字段都指定了文档关系。
@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[];
我不清楚如何使文档关系成为双向的。 我曾希望在文档上有一个字段,例如:
@ManyToOne(type => abstractEntity, entity => entity.document)
parentEntity: abstractEntity;
这样,如果我要查询文档实体的父关系, 我会得到如下结果:
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
]
但 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[];
为了简单起见,本示例中没有 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;
您的PostEntity
看起来像这样:
@Entity()
class PostEntity
@PrimaryGeneratedColumn()
public id!: number;
@Column()
public name: string;
public documents?: DocumentEntity[];
您可能会注意到,帖子上的文档没有注释。那是因为我们将使用上述方法进行连接。您的查询看起来像这样:
connection
.getRepository(PostEntity)
.createQueryBuilder('p')
.leftJoinAndMapMany(
'p.documents',
DocumentEntity,
'p__d',
'(p.id = md.entityId AND md.entity = :documentEntity)',
documentEntity: PostEntity.name,
,
)
.getMany()
这些方法可用于加入这些实体:
leftJoinAndMapMany
innerJoinAndMapMany
leftJoinAndMapOne
innerJoinAndMapOne
【讨论】:
嗨蒂姆,谢谢你的回答。但是恐怕您误解了这个问题,这可能写得不够清楚。问题不在于需要在 post 端指定额外的字段,leftJoinAndMap 确实有助于解决,而是不想在文档端创建额外的字段。但是这个元必须在某个地方定义。您仍在查询帖子,我仍然需要在文档上创建其他字段以显示文档填充的字段“角色”(对于引用文档的所有其他实体,“默认”、“特色”、“其他”等) 也许这有助于更清楚地说明:想象现在我定义了一个额外的实体“用户”。 “用户”具有字段“featuredProfile”,该字段也与文档有关系。我如何查询文档以返回所有文档及其父实体。目前我的结论是,在没有自定义连接表或某种手动“灵活”字段的 typeORM 中,这是不可能的,它存储实体类型及其 ID 列表,然后可以在自定义查询中使用,以上是关于TypeORM:如何实现双向关系,多个字段 --> 一种实体类型的主要内容,如果未能解决你的问题,请参考以下文章
如何创建如何在 typeorm 中创建多对多关系,[NestJS]
TypeORM getRepository.find() 不包括外键字段