GORM Playground Link
https://github.com/go-gorm/playground/pull/318
Description
I want to make some modifications to the Model inside the BeforeDelete hook. For example, to set the value of column DeletedBy and keep the normal behavior of gorm to update the DeletedAt (soft delete). However, I can't find a way to do this. I tried many approaches and combinations and tried to copy some code from SoftDeleteDeleteClause.ModifyStatement(), but nothing worked for me.
I expect BeforeDelete to behave similar to how BeforeCreate or BeforeUpdate works:
func (u *User) BeforeDelete(tx *gorm.DB) error {
u.DeletedBy = "gabriel" // Model should be updated here for all records in this transaction
return nil
}
Comment From: doppl-neal
I have the same issue. The BeforeDelete hook gets called, however, no data appears to be persisted. I also need to add to the filter - I have a built a multi tenant application and need to add the tenant id to the filter I got around this by creating a build condition if conds := tx.Statement.BuildCondition(query, {data}); len(conds) > 0 { tx.Statement.AddClause(clause.Where{Exprs: conds}) }
and I would like to do what gabriel376 in adding other data(time, and who deleted the record)
Comment From: s-takehana
There may be a better way.
package main
import (
"fmt"
"gorm.io/driver/postgres"
"gorm.io/gorm"
"gorm.io/gorm/clause"
)
type User struct {
gorm.Model
Name string
DeletedBy string
}
func (u *User) BeforeDelete(tx *gorm.DB) (err error) {
curTime := tx.Statement.DB.NowFunc()
deletedBy := "User0"
tx.Statement.AddClause(clause.Update{})
tx.Statement.AddClause(clause.Set{
{Column: clause.Column{Name: "deleted_at"}, Value: curTime},
{Column: clause.Column{Name: "deleted_by"}, Value: deletedBy},
})
tx.Statement.SetColumn("deleted_at", curTime)
tx.Statement.SetColumn("deleted_by", deletedBy)
tx.Statement.AddClause(clause.Where{Exprs: []clause.Expression{
clause.Eq{Column: clause.PrimaryColumn, Value: u.ID},
clause.Eq{Column: "deleted_at", Value: nil},
}})
tx.Statement.Build(
clause.Update{}.Name(),
clause.Set{}.Name(),
clause.Where{}.Name(),
)
return
}
func main() {
dsn := "host=postgres user=postgres password=***** dbname=postgres port=5432"
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
panic("failed to connect database")
}
db.AutoMigrate(&User{})
user := User{Name: "User1"}
db.Debug().Create(&user)
db.Debug().Delete(&user)
fmt.Printf("\n%+v\n", user)
}
2021/06/09 20:48:40 /workspace/main.go:55
[4.296ms] [rows:1] INSERT INTO "users" ("created_at","updated_at","deleted_at","name","deleted_by") VALUES ('2021-06-09 20:48:40.125','2021-06-09 20:48:40.125',NULL,'User1','') RETURNING "id"
2021/06/09 20:48:40 /workspace/main.go:57
[3.571ms] [rows:1] UPDATE "users" SET "deleted_at"='2021-06-09 20:48:40.13',"deleted_by"='User0' WHERE "users"."id" = 1 AND "deleted_at" IS NULL
{Model:{ID:1 CreatedAt:2021-06-09 20:48:40.1254744 +0000 UTC UpdatedAt:2021-06-09 20:48:40.1254744 +0000 UTC DeletedAt:{Time:2021-06-09 20:48:40.1300705 +0000 UTC Valid:true}} Name:User1 DeletedBy:User0}
Comment From: KiddoV
Solution https://github.com/go-gorm/gorm/issues/4347#issuecomment-858081913 above is just a work around (and really bad work-around with hardcoded value), is there any plan to make it more like BeforeCreate or BeforeUpdate hook?