问题背景
在使用gorm时,往往默认的数据类型不满足我们的要求,需要使用一些自定义数据类型作为字段类型,并需要设置一些默认值,如下面例子。
定义一个Status数据类型和LocalTime数据类型,分别表示状态和时间,并实现Valuer和Scanner接口(不了解的话可以看gorm自定义数据类型官方文档)
说一下我自定义这两个数据类型的目的,想通过定义Status实现枚举,定义LocalTime实现时间的读取格式化
type Status int64 const ( TaskStatusDisabled Status = 0 // 禁用 TaskStatusFailure Status = 1 // 失败 ) func (s Status) Value() (driver.Value, error) { return int64(s), nil } func (s *Status) Scan(value interface{ }) error { v, ok := value.(int64) if ok { *s = Status(v) return nil } return errors.New("CustomizeDataTypeError") } type LocalTime time.Time func (t LocalTime) Value() (driver.Value, error) { var zeroTime time.Time tlt := time.Time(t) if tlt.UnixNano() == zeroTime.UnixNano() { return nil, nil } return tlt, nil } func (t *LocalTime) Scan(v interface{ }) error { if value, ok := v.(time.Time); ok { *t = LocalTime(value) return nil } return fmt.Errorf("can not convert %v to timestamp", v) } //实现时间格式化 func (t *LocalTime) MarshalJSON() ([]byte, error) { tTime := time.Time(*t) return []byte(fmt.Sprintf("\"%v\"", tTime.Format("2006-01-02 15:04:05"))), nil }
在声明模型时使用这个Status和LocalTime,这里省略一些其他字段
type Task struct { ... Status Status `json:status gorm:"default 0"` StartTime *LocalTime `json:"start_time" gorm:"notnull"` ... }
正题来了!!(前面铺垫有点长…)
当我们设置默认值的时候,对于
基本数据类型
int、string、bool这些自定义数据类型可以在gorm:”default ##”后面直接设置对应的默认值就可以了,在插入数据时会系统会自动识别,并插入到DB,如上面定义的Status,配置gorm:”default 0″就可以实现Debug时发现会将
0
识别为TaskStatusDisabled
常量
但是
对于一些引用类型就不能直接设置默认值了,比如我想将LocalTime设置默认值
如我们想这么设置
gorm: "default time.Parse('2006-01-02 15:04:05', '2999-12-31 23:59:59')"
或
gorm: "default LocalTime(time.Parse('2006-01-02 15:04:05', '2999-12-31 23:59:59'))"
- 统统不起作用
解决方案
GORM提供了我们解决方案,钩子
,官方文档链接
官方给出了如下说明
那我们可以通过在BeforeCreate方法中实现调用create方法前设置LocalTime的默认值
func (t *Task) BeforeCreate(tx *gorm.DB) error {
endTime, _ := time.Parse("2006-01-02 15:04:05", "2999-12-31 23:59:59")
et := LocalTime(endTime)
t.EndTime = &et
return nil
}
注意:虽然我没用
tx *gorm.DB
这个参数,但是这个参数也是必须要有的
说道这里,我们就可以发现这个钩子方法不仅仅可以设置默认值这么简单,可以调用tx.Update(),tx.Delete()等等方法,并且这些操作在一个事务内,更可以在这里做自己想做的任何事情。