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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With