DeleteAt
基于原生 GORM,model 中添加 gorm.DeleteAt 字段,从而自动获取 Soft-Delete 的能力。
// gorm.Model (注:在 gorm 项目的 model.go 中)
type Model struct {
ID uint `gorm:"primaryKey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
}
type UserV1 struct {
gorm.Model
Name string
}
// equals
type UserV2 struct {
ID uint `gorm:"primaryKey"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt `gorm:"index"`
Name string
}
原生GORM,当我们调用 Delete 时, 指定的记录并不会从数据库中物理删除,而是会将 gorm.DeleteAt 字段的值设置为当前时间,在一般情况下,调用查询方法时不会被返回。
内部适配:
// user's ID is `111`
db.Delete(&user)
// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE id = 111;
// Batch Delete
db.Where("age = ?", 20).Delete(&User{})
// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE age = 20;
// Soft deleted records will be ignored when querying
db.Where("age = 20").Find(&user)
// SELECT * FROM users WHERE age = 20 AND deleted_at IS NULL;
原来的 Delete 调用会被转换为一次 Update,自动处理了 delete_at 字段的更新逻辑。查询的时候,如果发现 model 中包含 gorm.DeleteAt 字段,也会自动加上 deleted_at IS NULL 作为 Where 条件。
如果需要查询到已经被软删除的记录,在 GORM 查询时加上 Unscoped
db.Unscoped().Where("age = 20").Find(&users)
// SELECT * FROM users WHERE age = 20;
扩展库
- DeletedAt (timestamp): NULL vs DeletedTimestamp
- DeletedAt (int64): 0 vs DetetedUnixTime
- IsDel (bool): 0 vs 1
- IsDel (bool) + DelTime (timestamp): 0 vs 1
原生的软删除支持的类型仅为 sql.NullTime,对应到第一种。
替换类型从 gorm.DeleteAt 换成 soft_delete.DeleteAt:
import "gorm.io/plugin/soft_delete"
type User struct {
ID uint
Name string `gorm:"uniqueIndex:udx_name"`
DeletedAt soft_delete.DeletedAt `gorm:"uniqueIndex:udx_name"`
}
Unix second
DeletedAt soft_delete.DeletedAt 默认按照 unix 时间戳来判断,对应到第二种
时间戳支持秒、毫秒、纳秒,通过 softDelete tag 来指明:gorm:"softDelete:xx"
type User struct {
ID uint
Name string
DeletedAt soft_delete.DeletedAt `gorm:"softDelete:milli"`
// DeletedAt soft_delete.DeletedAt `gorm:"softDelete:nano"`
}
// Query
SELECT * FROM users WHERE deleted_at = 0;
// Delete
UPDATE users SET deleted_at = /* current unix milli second or nano second */ WHERE ID = 1;
0/1 flag
对应第三种模式,使用 0 / 1 进行标识,只需要将 gorm:"softDelete:xxxx"
中的值,从上面时间戳的 milli/nano 替换为 flag 。
import "gorm.io/plugin/soft_delete"
type User struct {
ID uint
Name string
IsDel soft_delete.DeletedAt `gorm:"softDelete:flag"`
}
// Query
SELECT * FROM users WHERE is_del = 0;
// Delete
UPDATE users SET is_del = 1 WHERE ID = 1;
混合模式
对应第四种,一般情况不推荐使用。需要两个字段,一个承载 flag 的能力,一个承载时间戳。 可以通过 gorm 的 tag 来适配。
type User struct {
ID uint
Name string
DeletedAt time.Time
IsDel soft_delete.DeletedAt `gorm:"softDelete:flag,DeletedAtField:DeletedAt"` // use `1` `0`
// IsDel soft_delete.DeletedAt `gorm:"softDelete:,DeletedAtField:DeletedAt"` // use `unix second`
// IsDel soft_delete.DeletedAt `gorm:"softDelete:nano,DeletedAtField:DeletedAt"` // use `unix nano second`
}
// Query
SELECT * FROM users WHERE is_del = 0;
// Delete
UPDATE users SET is_del = 1, deleted_at = /* current unix second */ WHERE ID = 1;