Cascading Soft Delete

Cascading Soft Delete

I hate to say it but triggers are designed specifically for this kind of thing.

(The hate part is because good triggers are very hard to write and , of course , cannot be debugged)

Laravel 5: cascade soft delete

I have put this code in Offer model:

protected static function boot() {
parent::boot();

static::deleting(function($offer) {
$offer->services()->delete();
});
}

And added missing

use SoftDeletes;
protected $dates = ['deleted_at'];

in the Service model.

How to use Cascade Soft Delete Trait in laravel 8?

Cascading deletes are handled at the database-level, so when you set onDelete('cascade') in your migration, that translates to your database deleting any records attached by foreign key.

Soft deletes are handled by the application, so you'd either need to fire an event on the parent model and listen for it on the children or, in your parent model, bind the static::deleted() method in the boot method, and delete the relationships there.

I'm not sure if you could do something like:

public static function boot()
{
parent::boot();

static::deleted(function ($model) {
// Probably lazy load these relationships to avoid lots of queries?
$model->load([ 'relationshipOne', 'relationshipTwo', ]);

$model->relationshipOne()->delete();
$model->relationshipTwo()->delete();
});
}

Or if you'd have to iterate over the related items:

public static function boot()
{
parent::boot();

static::deleted(function ($model) {
$model->relationshipOne->each(function ($item) {
$item->delete();
});

$model->relationshipTwo->each(function ($item) {
$item->delete();
});
});
}

How do I Cascade a SoftDelete?

After reading this SO Article entity-framework-6-code-first-cascade-delete...

I realized, I was grabbing and and deleting my entity like this:

var entity = context.Parent.FirstOrDefault();
context.Parent.Remove(entity);

When I needed to grab the entire Graph like this:

var entity = context.Parent.Include("Children").FirstOrDefault();
context.Parent.Remove(entity);

Thank you for your input @Maarten

How to cascade (soft) delete has many relationships in GORM?

I found an solution, but I think it is not optimal for cascade delete, it solved my problem at least. I've coded the following:

First the DeleteProject function, where I loop over all Diagrams and call the DeleteDiagram function and finally I also clear all associations with this project before deleting the project.

//Delete a project and it's associations.
func DeleteProject(db *gorm.DB, id uint) (Project, error) {
project, err := GetProject(db, id)
if err != nil {
return Project{}, err
}
if len(project.Diagrams) > 0 {
for _, projectDiagram := range project.Diagrams {
_, err := DeleteDiagram(db, projectDiagram.ID)
if err != nil {
return Project{}, err
}
}
db.Model(&project).Association("Diagrams").Clear()
}
if err := db.Delete(&project, id).Error; err != nil {
return Project{}, err
}
return project, nil
}

The DeleteDiagram does the same, but then with the Instances

//Delete a diagram and it's associations.
func DeleteDiagram(db *gorm.DB, id uint) (Diagram, error) {
var diagram, err = GetDiagram(db, id)
if err != nil {
return Diagram{}, err
}
if len(diagram.Instances) > 0 {
db.Model(&diagram).Association("Instances").Clear()
for _, diagramInstance := range diagram.Instances {
_, err := DeleteInstance(db, diagramInstance.ID)
if err != nil {
return Diagram{}, err
}
}
}
if err := db.Delete(&diagram).Error; err != nil {
return Diagram{}, err
}
return diagram, nil
}

Hope it helps.

Soft delete cascade not working

A soft delete means gorm do not remove your data. It only mark a non-zero DeleteAt timestamp. That is not supported by database directly. So foreign key has no effect here.

That means you need to manually implement the cascaded delete yourself, like this:

func DeleteUser(db *gorm.DB, id int) error {
tx := db.Begin()
if tx.Where("id = ?", id).Delete(&User{}); tx.Error != nil {
tx.Rollback()
return tx.Error
}
// Changed this line
// if tx.Where("user_id = id", 3).Delete(&Calendar{}); tx.Error != nil {
if tx.Where("user_id = ?", id).Delete(&Calendar{}); tx.Error != nil {
tx.Rollback()
return tx.Error
}
return tx.Commit().Error
}


Related Topics



Leave a reply



Submit