Describe the feature
Model A has many Model B, Model B has many Model C
If Model A was deleted, Model B and Model C both should be able to be deleted by cascade
Motivation
Related Issues
6346, #6344, go-orm/playground PR
Comment From: pplmx
FYI.
Here is a demo implemented by Spring JPA, which implements the above requirement.
Comment From: Shahriar-Sazid
You can achieve this by after delete hook.
type ModelA struct {
ID uint
ModelBList []ModelB
}
type ModelB struct {
ID uint
ModelAID uint
ModelCList []ModelC
}
type ModelC struct {
ID uint
ModelBID uint
}
func (m *ModelA) AfterDelete(tx *gorm.DB) (err error) {
tx.Clauses(clause.Returning{}).Where("model_a_id = ?", m.ID).Delete(&ModelB{})
return
}
func (m *ModelB) AfterDelete(tx *gorm.DB) (err error) {
tx.Clauses(clause.Returning{}).Where("model_b_id = ?", m.ID).Delete(&ModelC{})
return
}
Comment From: pplmx
Thanks a lot. :)
Comment From: pplmx
If you wanna delete it, not only just removing the reference, you should do the following:
- Since the foreign key constraint, use the
BeforeDeleteinstead ofAfterDelete
package model
import (
"fmt"
"gorm.io/gorm"
)
type ModelA struct {
ID uint
ModelBList []ModelB
}
type ModelB struct {
ID uint
ModelAID uint
ModelCList []ModelC
}
type ModelC struct {
ID uint
ModelBID uint
}
// BeforeDelete for ModelA
func (a *ModelA) BeforeDelete(tx *gorm.DB) (err error) {
// 1. if ID is 0, return
if a.ID == 0 {
return
}
// 2. delete its ModelBList
// DO NOT USE
//if err = tx.Clauses(clause.Returning{}).Where("model_a_id = ?", a.ID).Delete(&ModelB{}); err != nil {
// return fmt.Errorf("failed to delete model b list: %w", err)
//}
// NOTES: please use this way to delete model b list,
// which aims to get model b id when running ModelB BeforeDelete hook
// USE IT
if err = tx.Model(a).Association("ModelBList").Find(&a.ModelBList); err != nil {
return fmt.Errorf("failed to find model b list when deleting model a: %w", err)
}
for _, b := range a.ModelBList {
if err = tx.Delete(b).Error; err != nil {
return fmt.Errorf("failed to delete model b[%d] in model a[%d]: %w", b.ID, a.ID, err)
}
}
return
}
// BeforeDelete for ModelB
func (b *ModelB) BeforeDelete(tx *gorm.DB) (err error) {
// 1. if ID is 0, return
if b.ID == 0 {
return
}
// 2. delete its ModelCList
if err = tx.Model(b).Association("ModelCList").Find(&b.ModelCList); err != nil {
return fmt.Errorf("failed to find model c list when deleting model b: %w", err)
}
for _, c := range b.ModelCList {
if err = tx.Delete(c).Error; err != nil {
return fmt.Errorf("failed to delete model c[%d] in model b[%d]: %w", c.ID, b.ID, err)
}
}
return
}