go-gorm/gorm.io

Gorm Delete Associations with Select triggers hook with an empty object receiver

duke-alibubu opened this issue · 2 comments

When deleting associations with Select, the association's hook will be triggered, but with an empty object receiver.

For example, if we have the following structs:

type Party struct {
	ID   uint64
	Name string
	Dogs []Dog
}

type Dog struct {
	ID      uint64
	Breed   string
	Age     uint64
	PartyID uint64
}

Dog struct has a BeforeDelete hook like this:

func (d *Dog) BeforeDelete(tx *gorm.DB) error {
	fmt.Println(d)
	return nil
}

When the progream deletes the associations with tx.Select("Dogs").Delete(p) - BeforeDelete hook will be fired, with an empty receiver. In the above example, the value printed out is: &{0 0 0}.

The full example is given here: https://github.com/duke-alibubu/gorm_select_delete_issue/blob/master/main.go

My own speculation is probably under the hood, Delete Associations will fire db.Where("associate_id = ?", aid).Delete(&Model{}) thus triggering hooks on an empty object. However, this behaviour is not good and should be improved - like firing the hook with the proper object receiver, or just skip the hooks when deleting associations.

is there any solution?

Think of it as a call chain.

type ObjectA struct {
	gorm.Model
	Name    string
	ObjectB []ObjectB `gorm:"foreignKey:ObjectAID"`
}

type ObjectB struct {
	gorm.Model
	ObjectAID uint32 `gorm:"column:object_a_id"`
	Name      string
}

func deletionCall(db *gorm.DB) {
	_ = db.Clauses(clause.Returning{Columns: []clause.Column{{Name: "id"}}}).
		Where("id", 1).
		Delete(&ObjectA{}).Error
}

func (a *ObjectA) AfterDelete(tx *gorm.DB) (err error) {
	tx.
		// if we have a trigger on ObjectA we can chain again as commented
		// Clauses(clause.Returning{Columns: []clause.Column{{Name: "id"}}}).
		Where("object_a_id = ?", a.ID).Delete(&ReturnablesCustomerLedger{})
	return
}