typeorm: SoftDelete in relationships cascade does not work
Issue type:
[ ] question [x] bug report [ ] feature request [ ] documentation issue
Database system/driver:
[ ] cordova
[ ] mongodb
[ ] mssql
[x] mysql / mariadb
[ ] oracle
[ ] postgres
[ ] cockroachdb
[ ] sqlite
[ ] sqljs
[ ] react-native
[ ] expo
TypeORM version:
[ ] latest
[ ] @next
[ ] 0.2.24 (or put your version here)
In one to many relationship the sofdelete does not update the related entity:
The Gestion entity has a one-to-many relationship with the Incedence entity
Gestion entity
....
@DeleteDateColumn({ type: "datetime" })
deletedAt: Date;
....
@OneToMany(type => Incidence, incidence => incidence.gestion,{
cascade: true
})
incidences: Incidence[];
Inverse relationship
Incidence entity
...
@DeleteDateColumn({ type: "datetime" })
deletedAt: Date;
...
@ManyToOne(type => Gestion, gestion => gestion.incidences)
gestion: Gestion;
await gestRepository.softDelete({id:gestionId})
The deleteAt column of the Gestion entity is set correctly with the date but the related entity Incidence is not affected, it remains null
About this issue
- Original URL
- State: open
- Created 4 years ago
- Reactions: 4
- Comments: 28 (3 by maintainers)
Immediately after posting I discovered that if I include the relations in my original query then the cascade deletes will work.
For example, the following did not soft delete the children:
Then by adding the relations it did:
My entities are as follows:
Also to note, the only way to get the cascade to work properly is to use
softRemoveand pass the entire entity in with all children. e.g.repo.softRemove(parent)whereparentcontains all children. I suppose this makes sense, otherwise thesoftRemovemethod would have to perform additional queries for all children and nested children, but the behavior isn’t very intuitive or helpful seeing as one could simply query the children separately and pass them torepo.softRemove().To complement @manymikes answer, I was able to solve this issue put a
cascade: truein myOneToOnedecorator with theonDelete: "CASCADE"option.@johncmunson You need to add the
relationskey to yourfindOneoptions just as @mikehroth did in his example.Please let me know if this solves your issue
Ok, in your example it works if I change something on parent. In this case, I don’t want to change anything except deletedAt which is done by softRemove().
It’s a part of a feature that receive an event when a guild leave, find if settings for this guild exist, if yes softRemove it and softremove all guild’s members settings too.
Because softRemove() change something on the parent (the deletedAt column), I was thinking this will propagate the fact that parent is softRemoved and childrens need to be softRemoved too.
@woobottle I don’t think it makes sense logically to put both
cascadeandonDeleteto your parent entity. They are 2 different things.cascadeoption allows you to save changes applied to children/relation objects whenever you do something on that field within the parent.cascade: trueon a OneToMany relation (parent->children) such as above, then doingparent.children = [new array of children entities]and saving that parent, means the children get updated/inserted/removed automatically (based on what you changed & also what you allow via thecascadeoption)onDelete(and otheronSomethingoptions) should be set on the children (the Many side of OneToMany) and dictates what happens with the children when something happens to the parentonDelete: 'CASCADE'on the child entity would delete those related children if the parent gets deleted.I’m not really sure how (or why)
onDelete: 'CASCADE'would work on the parent side of the relation. What would be expected? If you delete any of the children the parent gets deleted too? (and then the rest of children as well?)first. set cascade and delete in entity second. find with relations and soft remove this it will work i will add my code
// users.entity
// soft remove part
This works but why do we need to find with relations and then do the softRemove? Could it be possible to soft delete records without finding them first? Maybe @pleerock can help here!
Thanks in advance.
Thank you @Alkadian. I have not had a chance to try out @mikehroth’s solution. But, assuming it does work, it’s still problematic because the parent entity is required to have too much knowledge of it’s children. Think about how the relationship works in normal SQL…
It’s the child that gets to dictate what happens when the parent is deleted, and not the other way around.
With some effort, I was able to come up with my own soft delete solution that preserves the proper parent/child semantics. Basically, it involved creating a base repository that all other entities inherit from. The base repo contains a softDelete method and a restore method, each of which emit an event when they are called. This concept was combined with a custom
@OnSoftDeletedecorator that registers an event listener.That way, the child entities can decorate their foreign keys if they want to opt-in to soft deletes.
Unfortunately, I wasn’t able to utilize TypeORM’s built-in event system for this feature, and had to roll my own events and listeners. This is because the TypeORM event system has some very questionable design decisions baked in and is very inconsistent.
Without cascade, your change about the related objects will not be saved.
Working as expected
softdelete
Log
@johncmunson could you provide a sample code for the listeners and event emitters?
Have same issue with postgres too
It is not working in my case: (node:29864) UnhandledPromiseRejectionWarning: Error: Cannot query across one-to-many for property ITEMS)
And setting cascade on both entities throws an error too. Can be only set on the parent
For
cascade: true, when we soft delete the parent, we also soft delete the child. Is there a way we can soft delete the parent and cascade to hard delete its children?Given the following two entities,
CategoryandCoffee…And given the following code…
I would expect for the
deletedDatefield to be updated for the ‘Dark Roast’Category, and for all of the childCoffeeentities that have aCategoryof “Dark Roast”.However, this is not what happens. The
Categoryentity is the only thing that gets soft deleted.Therefore, what the heck is the point of
{cascade: ['soft-remove']}??Would love it if someone were able to point out something I’m doing wrong in my example, but as it stands… it definitely seems like the soft delete functionality in TypeORM is not yet fully baked, especially cascading soft deletes.