Reputation: 1478
I can not figure out if it is me, of cascade: true
option does not delete children entities when removing parent one?
@Entity()
export class Folder {
@PrimaryGeneratedColumn()
public readonly id: number;
@OneToMany(() => Segment, (segment) => segment.folder, {
cascade: true,
})
public segments: Segment[];
}
@Entity()
export class Segment {
@PrimaryGeneratedColumn()
public readonly id: number;
@ManyToOne(() => Folder, (folder) => folder.segments)
@JoinColumn()
public folder: Folder;
}
and then I do
await getRepository(Folder).delete(id);
which gives me an error:
update or delete on table "folder" violates foreign key constraint "FK_12606f83d18e5ae0c7e5693f3fb" on table
"segment"
Also tried to do
const folder = await this.repository.findOneOrFail(id);
repository.remove(folder)
//or
folder.segments = null;
await this.repository.save(folder);
still error...
I don't want to loop through all children entities and remove them manually. I thought cascade: true
should handle it as well as saving or updating.
Maybe syntax supposes to be different?
Thanks!
Upvotes: 11
Views: 21135
Reputation: 59
TLDR: use Repository.softRemove(entityWithRelations)
You want to pass in the response from a query which includes the relations that you hope to cascade the operation on.
...
I tried the { onDelete: 'CASCADE' }
but that only worked for doing a hard delete and we need this to do soft-delete in order to be able to restore the entities in the database.
I found that I had to use the soft-remove or remove on the repository instead of delete or soft-delete which do not cascade any database actions to nested/child entities.
this also makes sense since the typeORM options for cascade include 'soft-remove', and not 'soft-delete'.
Upvotes: 0
Reputation: 1
To cascade delete all the related entities here are the steps. My case is that when I delete a signal, its signalDetail, signalClassificationJoins, signalPostJoin, and the posts should be deleted.
here is the signal entity
@OneToMany(
() => SignalClassificationJoin,
(SignalClassificationJoin) => SignalClassificationJoin.signal,
{
cascade: true,
lazy: false,
}
)
classificationDetails: SignalClassificationJoin[];
@OneToOne(() => SignalDetail, (SignalDetail) => SignalDetail.signal, {
cascade: true,
lazy: false,
})
signalDetail: SignalDetail;
@OneToMany(() => SignalPostJoin, (SignalPostJoin) => SignalPostJoin.signal, {
cascade: true,
lazy: false,
})
signalPostJoin?: SignalPostJoin[];
with the related entities when you are defining the inverse relation do it as
@ManyToOne(() => Signal, (Signal) => Signal.classificationDetails, {
onDelete: "CASCADE",
})
@JoinColumn({ name: "signal_id" })
signal: Signal;
and finally, delete the signal with the related entities as follows by including all the nested relations you want to delete
const signal = await this.signalRepository.findOne({
where: { id },
relations: {
classificationDetails: true,
signalDetail: true,
signalPostJoin: { posts: true },
},
});
const deletedSignal = await this.signalRepository.remove(signal);
Upvotes: 0
Reputation: 69
- Parent Entity
@OneToMany(type => Comment, comment => comment.parent, { cascade: ["remove"] })
replies: Comment[];
Create cascade option in @OneToMany relation.
@OneToMany relation onDelete option is not needed.
{ cascade: ["remove"] }
- Child Entity
@ManyToOne(type => Comment, comment => comment.replies, { onDelete: "CASCADE" })
parent: Comment;
Create onDelete option in @ManyToOne relation.
@ManyToOne relation cascade option is not needed.
{ onDelete: "CASCADE" }
Upvotes: 3
Reputation: 14792
Parent Entity => set cascade to "remove"
// Parent Entity
@OneToMany(type => Comment, comment => comment.parent,{ cascade: ["remove"] })
replies: Comment[];
Child Entity => set onDelete to CASCADE
and orphanedRowAction to delete
.
// Child Entity
@ManyToOne(type => Comment, comment => comment.replies, {
onDelete: "CASCADE", orphanedRowAction: 'delete'
})
parent: Comment;
When you want to delete Parent with its children you have to do as follows:
await ParentRepository.delete(parentId)
Upvotes: 6
Reputation: 552
This is a "bug" (not sure if it's the the desired behavior) inside the typeorm code, I fixed this issue by using https://www.npmjs.com/package/patch-package because I needed this fix asap
You need to patch the file at node_modules/typeorm/persistence/subject-builder/OneToManySubjectBuilder.js
with this code (- is what you need to remove and + is what you need to add):
var removedRelatedEntitySubject = new Subject_1.Subject({
metadata: relation.inverseEntityMetadata,
parentSubject: subject,
- canBeUpdated: true,
+ canBeUpdated: !relation.isNullable,
+ mustBeRemoved: relation.isNullable,
Upvotes: 1
Reputation: 1849
Cascade only describes what to do with related entities, it doesn't have an effect when the entity itself is deleted. If you want to delete all segments when deleting a folder you need to use onDelete (this is a database feature, otherwise then cascade, which is implemented within TypeORM. This means you need to generate and execute migrations when adding onDelete). So this should work for you:
@Entity()
export class Segment {
@PrimaryGeneratedColumn()
public readonly id: number;
@ManyToOne(() => Folder, (folder) => folder.segments, { onDelete: 'CASCADE' })
@JoinColumn()
public folder: Folder;
}
Upvotes: 13