TypeORM is a very convenient ORM for JS apps. We use it with NestJS and running it on NodeJS.
But we are not here to talk about our technical stack, but to deep dive, directly into relations with TypeORM.
When you are referencing children entities from a parent entity, you use a @OneToMany
relation and a @ManyToOne
relation.
import {Entity, Column, ManyToOne, OneToMany, PrimaryGeneratedColumn} from "typeorm";
@Entity()
export class ParentEntity {
@PrimaryGeneratedColumn()
id: number;
@OneToMany(
() => ChildEntity,
child => child.parent
)
children: ChildEntity[];
}
@Entity()
export class ChildEntity {
@PrimaryGeneratedColumn()
id: number;
@ManyToOne(
() => ParentEntity,
parent => parent.children,
{nullable: false}
)
parent: ParentEntity;
}
And the best part referencing children entities in the parent entity, is that you can manipulate children to add, remove or update them.
If you add {cascade: true}
, every change in children will be saved when you save the parent.
Let's update the parent entity :
@Entity()
export class ParentEntity {
@PrimaryGeneratedColumn()
id: number;
@OneToMany(
() => ChildEntity,
child => child.parent,
{cascade: true}
)
children: ChildEntity[];
removeChild(childId: number): void {
// lets remove the target from the array
this.children = this.children.filter(child => child.id !== childId);
}
}
export class MyService() {
private parentEntity: ParentEntity;
constructor(private readonly parentRepository: Repository<ParentEntity>) {}
removeChildFromParent(childId: number) {
this.parent.removeChild(childId);
this.parentRepository.save(this.parent);
}
}
And now we are in troubles because this line this.parentRepository.save(this.parent);
will throw an error, because the default behaviour when you remove an entity from the array, is to set its property parent: ParentEntity;
to null and so the column in database called parent_id
which is not nullable 😨😱
How the hell are we gonna do ?
Nothing, end of thread, see ya.
Come back my friends, we have a solution, and it's not well documented yet in the TypeORM doc :)
It's the magical option orphanedRowAction
that will save us, but its default value that is causing our troubles : nullify
.
orphanedRowAction: "nullify" | "delete" | "soft-delete" | disable
- When a parent is saved (cascading enabled) without a child/children that still exists in database, this will control what shall happen to them.
All you have to do is to use it in the child entity relation to its parent (that the unclear point in TypeORM's doc to me) :
@Entity()
export class ChildEntity {
@PrimaryGeneratedColumn()
id: number;
@ManyToOne(
() => ParentEntity,
parent => parent.children,
{
nullable: false,
orphanedRowAction: "delete"
}
)
parent: ParentEntity;
}
So now when you remove an entity from the parent's children
array, there'll be a DELETE
query to remove it from database.
And now, your mind is free.
Top comments (0)