本来应该写Docker的,但是想了下,还是决定先做好开发,最后部署Docker。
这里先提出问题,我们models目录下的 tag.go、 article.go 文件,它们有两个方法:AfterCreate、AfterUpdate。
每个文件都要实现这两个办法?
目标
通过GORM的 Callbacks 来实现功能,不需要编写每个文件。
功能
每次 create 更新 CreatedOn 字段。
每次 update 更新 ModifiedOn 字段。
实现Callbacks
参考文档还是 gorm.io .
参考地址1:https://gorm.io/zh_CN/docs/write_plugins.html
参考地址2:https://gorm.io/docs/update.html#Change-Updating-Values
参考地址3:https://github.com/go-gorm/gorm/issues/3441
参考地址4:https://gorm.io/zh_CN/docs/hooks.html
这里我们需要针对 before_create 和 before_update 两个Callback实现
在models/models.go 文件中增加两个函数:
models/models.go
Go
func updateTimeStampForBeforeCreateCallback(db *gorm.DB) {
db.Statement.SetColumn("CreatedOn", time.Now().Unix())
}
func updateTimeStampForBeforeUpdateCallback(db *gorm.DB) {
db.Statement.SetColumn("ModifiedOn", time.Now().Unix())
}
1
2
3
4
5
6
7
funcupdateTimeStampForBeforeCreateCallback(db *gorm.DB){
db.Statement.SetColumn("CreatedOn",time.Now().Unix())
}
funcupdateTimeStampForBeforeUpdateCallback(db *gorm.DB){
db.Statement.SetColumn("ModifiedOn",time.Now().Unix())
}
SetColumn函数实际上是GORM包实现的一个辅助函数,内容如下:
Go
// Helpers
// SetColumn set column's value
func (stmt *Statement) SetColumn(name string, value interface{}) {
if v, ok := stmt.Dest.(map[string]interface{}); ok {
v[name] = value
} else if stmt.Schema != nil {
if field := stmt.Schema.LookUpField(name); field != nil {
switch stmt.ReflectValue.Kind() {
case reflect.Slice, reflect.Array:
field.Set(stmt.ReflectValue.Index(stmt.CurDestIndex), value)
case reflect.Struct:
field.Set(stmt.ReflectValue, value)
}
} else {
stmt.AddError(ErrInvalidField)
}
} else {
stmt.AddError(ErrInvalidField)
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Helpers
// SetColumn set column's value
func(stmt *Statement)SetColumn(namestring,valueinterface{}){
ifv,ok:=stmt.Dest.(map[string]interface{});ok{
v[name]=value
}elseifstmt.Schema!=nil{
iffield:=stmt.Schema.LookUpField(name);field!=nil{
switchstmt.ReflectValue.Kind(){
casereflect.Slice,reflect.Array:
field.Set(stmt.ReflectValue.Index(stmt.CurDestIndex),value)
casereflect.Struct:
field.Set(stmt.ReflectValue,value)
}
}else{
stmt.AddError(ErrInvalidField)
}
}else{
stmt.AddError(ErrInvalidField)
}
}
注册Callback
在 models.go 的 init 函数中增加以下语句:
Go
// 用新函数替换GORM Create、Update流程自带的回调函数
db.Callback().Create().Replace("gorm:before_create", updateTimeStampForBeforeCreateCallback)
db.Callback().Update().Replace("gorm:before_update", updateTimeStampForBeforeUpdateCallback)
1
2
3
// 用新函数替换GORM Create、Update流程自带的回调函数
db.Callback().Create().Replace("gorm:before_create",updateTimeStampForBeforeCreateCallback)
db.Callback().Update().Replace("gorm:before_update",updateTimeStampForBeforeUpdateCallback)
验证
访问AddTag接口,成功之后检查数据库,可以发现 created_on 字段为当前执行时间。
访问EditTag接口,可发现 modified_on 为最后一次执行更新的实际。
拓展
P.S. 其实我们实现的 CreatedOn、 ModifiedOn 以及这里要实现的 DeletedOn 都是GORM已经实现好的。
实际项目中,硬删除是比较少的,那么是否可以通过Callbacks来完成这个功能呢。
我们在先前 Model struct 增加 DeletedOn 变量。
models/models.go
Go
//Model ...
type Model struct {
ID uint `gorm:"primarykey" json:"id"`
CreatedOn int `json:"created_on"`
ModifiedOn int `json:"modified_on"`
DeletedOn int `json:"deleted_on"`
}
1
<