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
Schedule Import CSV to SQL Server 2014 Express Edition
SQL 2005 Force Table Rename That Has Dependencies
Query SQL to Subtract Two Fields
SQL Server 2008 Open Master Key Error Upon Physical Server Change Over
Sqllite Strftime Function to Get Grouped Data by Months
Implementing a Total Order Ranking in Postgresql 8.3
How to Check Type of Value in Postgres
How to Pass a Parameter from Vb.Net
Good Reasons Not to Use a Relational Database
SQL Update If Parameter Is Not Null or Empty
Difference Between Inner Join and Left Semi Join
How to Force a SQL Server 2008 Database to Go Offline
Using the Web.Config to Set Up My SQL Database Connection String
Remove Duplicates from SQL Union
Finding the Hash Value of a Row in Postgresql