什么是SoftDelete
SoftDelete软删除,即不真正删除数据,而在某行数据上增加类型is_deleted的删除标识,一般使用UPDATE语句。
启用Interceptor
在使用SoftDelete之前,首先需要启用Interceptor,即拦截器,SoftDelete正是Interceptor和Hook的典型示例
go run -mod=mod entgo.io/ent/cmd/ent generate --template glob="./rpc/ent/template/*.tmpl" ./rpc/ent/schema --feature sql/execquery,intercept
或者在Go-Zero的Makefile做如下修改(仅在使用Goctls的情况下支持)
# Ent enabled features | Ent 启用的官方特性 ENT_FEATURE=sql/execquery,intercept
添加之后执行 make gen-ent , 生成 Interceptor.
添加 Mixin
Ent提供了官方的Mixin,只需要引入即可。
// SoftDeleteMixin implements the soft delete pattern for schemas.
type SoftDeleteMixin struct {
mixin.Schema
}
// Fields of the SoftDeleteMixin.
func (SoftDeleteMixin) Fields() []ent.Field {
return []ent.Field{
field.Time("delete_time").
Optional(),
}
}
type softDeleteKey struct{}
// SkipSoftDelete returns a new context that skips the soft-delete interceptor/mutators.
func SkipSoftDelete(parent context.Context) context.Context {
return context.WithValue(parent, softDeleteKey{}, true)
}
// Interceptors of the SoftDeleteMixin.
func (d SoftDeleteMixin) Interceptors() []ent.Interceptor {
return []ent.Interceptor{
intercept.TraverseFunc(func(ctx context.Context, q intercept.Query) error {
// Skip soft-delete, means include soft-deleted entities.
if skip, _ := ctx.Value(softDeleteKey{}).(bool); skip {
return nil
}
d.P(q)
return nil
}),
}
}
// Hooks of the SoftDeleteMixin.
func (d SoftDeleteMixin) Hooks() []ent.Hook {
return []ent.Hook{
hook.On(
func(next ent.Mutator) ent.Mutator {
return ent.MutateFunc(func(ctx context.Context, m ent.Mutation) (ent.Value, error) {
// Skip soft-delete, means delete the entity permanently.
if skip, _ := ctx.Value(softDeleteKey{}).(bool); skip {
return next.Mutate(ctx, m)
}
mx, ok := m.(interface {
SetOp(ent.Op)
Client() *gen.Client
SetDeleteTime(time.Time)
WhereP(...func(*sql.Selector))
})
if !ok {
return nil, fmt.Errorf("unexpected mutation type %T", m)
}
d.P(mx)
mx.SetOp(ent.OpUpdate)
mx.SetDeleteTime(time.Now())
return mx.Client().Mutate(ctx, m)
})
},
ent.OpDeleteOne|ent.OpDelete,
),
}
}
// P adds a storage-level predicate to the queries and mutations.
func (d SoftDeleteMixin) P(w interface{ WhereP(...func(*sql.Selector)) }) {
w.WhereP(
sql.FieldIsNull(d.Fields()[0].Descriptor().Name),
)
}
如果使用为Goctls可以通过执行命令 goctls extra ent mixin -a soft_delete 来添加Mixin
修改 Service Context
在 service_context.go 中添加本地的 ent/runtime
路径: internal/svc/service_context.go
引用 Mixin
在需要添加软删除的 schema 引用 mixins
// 例子
func (Task) Mixin() []ent.Mixin {
return []ent.Mixin{
mixins.IDMixin{},
mixins.StatusMixin{},
mixins2.SoftDeleteMixin{},
}
}
最后更新Ent代码生成即可
注意事项
由于添加软删除后会添加 deleted_at 字段,所以需要重新初始化数据库,