3.10 定制 GORM Callbacks
项目地址:https://github.com/EDDYCJY/go-gin-example
涉及知识点
GORM
本文目标
GORM itself is powered by Callbacks, so you could fully customize GORM as you want
GORM 本身是由回调驱动的,所以我们可以根据需要完全定制 GORM,以此达到我们的目的,如下:
注册一个新的回调
删除现有的回调
替换现有的回调
注册回调的顺序
在 GORM 中包含以上四类 Callbacks,我们结合项目选用 “替换现有的回调” 来解决一个小痛点。
问题
在 models 目录下,我们包含 tag.go 和 article.go 两个文件,他们有一个问题,就是 BeforeCreate、BeforeUpdate 重复出现了,那难道 100 个文件,就要写一百次吗?
1、tag.go

2、article.go

显然这是不可能的,如果先前你已经意识到这个问题,那挺OK,但没有的话,现在开始就要改
解决
在这里我们通过 Callbacks 来实现功能,不需要一个个文件去编写
实现Callbacks
打开 models 目录下的 models.go 文件,实现以下两个方法:
1、updateTimeStampForCreateCallback
在这段方法中,会完成以下功能
检查是否有含有错误(db.Error)
scope.FieldByName通过scope.Fields()获取所有字段,判断当前是否包含所需字段field.IsBlank可判断该字段的值是否为空若为空则
field.Set用于给该字段设置值,参数为interface{}
2、updateTimeStampForUpdateCallback
scope.Get(...)根据入参获取设置了字面值的参数,例如本文中是gorm:update_column,它会去查找含这个字面值的字段属性scope.SetColumn(...)假设没有指定update_column的字段,我们默认在更新回调设置ModifiedOn的值
注册Callbacks
在上面小节我已经把回调方法编写好了,接下来需要将其注册进 GORM 的钩子里,但其本身自带 Create 和 Update 回调,因此调用替换即可
在 models.go 的 init 函数中,增加以下语句
验证
访问 AddTag 接口,成功后检查数据库,可发现 created_on 和 modified_on 字段都为当前执行时间
访问 EditTag 接口,可发现 modified_on 为最后一次执行更新的时间
拓展
我们想到,在实际项目中硬删除是较少存在的,那么是否可以通过 Callbacks 来完成这个功能呢?
答案是可以的,我们在先前 Model struct 增加 DeletedOn 变量
实现Callbacks
打开 models 目录下的 models.go 文件,实现以下方法:
scope.Get("gorm:delete_option")检查是否手动指定了delete_optionscope.FieldByName("DeletedOn")获取我们约定的删除字段,若存在则UPDATE软删除,若不存在则DELETE硬删除scope.QuotedTableName()返回引用的表名,这个方法 GORM 会根据自身逻辑对表名进行一些处理scope.CombinedConditionSql()返回组合好的条件SQL,看一下方法原型很明了scope.AddToVars该方法可以添加值作为SQL的参数,也可用于防范SQL注入
注册Callbacks
在 models.go 的 init 函数中,增加以下删除的回调
验证
重启服务,访问 DeleteTag 接口,成功后即可发现 deleted_on 字段有值
小结
在这一章节中,我们结合 GORM 完成了新增、更新、查询的 Callbacks,在实际项目中常常也是这么使用
毕竟,一个钩子的事,就没有必要自己手写过多不必要的代码了
(注意,增加了软删除后,先前的代码需要增加 deleted_on 的判断)
参考
本系列示例代码
文档
关于
修改记录
第一版:2018年02月16日发布文章
第二版:2019年10月01日修改文章
?
如果有任何疑问或错误,欢迎在 issues 进行提问或给予修正意见,如果喜欢或对你有所帮助,欢迎 Star,对作者是一种鼓励和推进。
我的公众号

Last updated
Was this helpful?