Reputation: 775
I've created a 'document' entity:
e.g.
@Entity()
export class Document {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@Column()
path: string;
...
}
Multiple documents can be related to different entity types: post, userProfile etc
in the post entity for example, I have several fields which all specify document relationships.
@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[];
I'm unclear how to make the document relationships bidirectional. I had hoped to have a single field on document like:
@ManyToOne(type => abstractEntity, entity => entity.document)
parentEntity: abstractEntity;
This way if I'm querying document entities for their parent relationships, I would have a result like:
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
}
]
But Typeorm seems to want me to define an exact matching field for each parent relationship field on documentEntity like:
@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[];
}
For the sake of simplicity in this example, there are no M:N relationships: document can have at most one parent.
It doesn't seem correct that I would have to define a new field on document entity, for every possible instance where a parent entity field references a document. A query on document would not return a list with one field defining the parent entity, instead I have to parse/aggregate an arbitrary number of fields.
I can't seem to find any tutorials/examples in which a single entity has many fields each referencing the same other entity, which is making me think my basic approach is flawed.
Upvotes: 9
Views: 5564
Reputation: 153
The secret ingridient is leftJoinAndMapMany
which allows you to join abitrary entities and map it onto attributes.
Here is what I would do in your case. The DocumentEntity
would look like that:
@Entity()
class DocumentEntity {
@PrimaryGeneratedColumn()
public id!: number;
@Column()
public entity!: string;
@Column({
name: 'entity_id',
})
public entityId!: string;
@Column()
public name!: string;
}
Your PostEntity
would look like that:
@Entity()
class PostEntity {
@PrimaryGeneratedColumn()
public id!: number;
@Column()
public name: string;
public documents?: DocumentEntity[];
}
As you might notice, the documents on the post has no anotation. Thats because we will do the join with the aforementioned method. Your query would look something like that:
connection
.getRepository(PostEntity)
.createQueryBuilder('p')
.leftJoinAndMapMany(
'p.documents',
DocumentEntity,
'p__d',
'(p.id = md.entityId AND md.entity = :documentEntity)',
{
documentEntity: PostEntity.name,
},
)
.getMany()
These methods are available for joining these entities:
leftJoinAndMapMany
innerJoinAndMapMany
leftJoinAndMapOne
innerJoinAndMapOne
Upvotes: 1