GORM自定义类型
官方也有一个用来收集自定义的类型的仓库:https://github.com/go-gorm/datatypes
场景
时间类型
初始的时间类型只有time.time类型,而我们习惯输入和展示的结构是形如 2023-04-08 12:12:12这种。
这种格式需要被程序转化为time.time类型被orm使用,从数据库查找的时候也需要做同样的转换。
// 我这里举个例子,当我收到json数据我会转成解析成如下结构体
type CreateOrderRequest struct {
OrderId int64 `json:"order_id"`
PartnerId int64 `json:"partner_id"` //客户
DateOrder DateTime `json:"date_order"` //订购日期
...
Products []OrderProduct `json:"products"`
Note string `json:"note"`
}
// 其中有个我自定义的类型DateTime
type DateTime time.Time
var TimeFormats = []string{"2006-01-02 15:04:05", "20060102150405"}
func (t *DateTime) UnmarshalJSON(data []byte) (err error) {
fmt.Println(string(data))
// 空值不进行解析
if len(data) == 2 {
*t = DateTime(time.Time{})
return
}
var now time.Time
for _, format := range TimeFormats {
// 指定解析的格式
if now, err = time.ParseInLocation(format, string(data), time.Local); err == nil {
*t = DateTime(now)
return
}
// 指定解析的格式
if now, err = time.ParseInLocation(`"`+format+`"`, string(data), time.Local); err == nil {
*t = DateTime(now)
return
}
}
return
}
//当我在添加数据库时
// CreateOrder 创建订单
func CreateOrder(info global.CreateOrderRequest, login_user_id int64) (oid int64, err error) {
...
order := model.SaleOrder{
Name: order_no,
...
DateOrder: time.Time(info.DateOrder),
...
}
if err = tx.Create(&order).Error; err != nil {
tx.Rollback()
return
}
...
}
//可以很方便的使用
//这种方式我比较推荐
使用自定义类型
我们可以自定义一个类型使得gorm可以直接识别字符串类型的时间格式,这里我只提供这种思路并不建议在实际情况中使用
//自定义的数据类型必须实现 Scanner 和 Valuer 接口,以便让 GORM 知道如何将该类型接收、保存到数据库
type DateTime string
// 实现 sql.Scanner 接口,Scan 将 value 扫描至
func (j *DateTime) Scan(value interface{}) error {
*j = DateTime((value.(time.Time)).Format("2006-01-02 15:04:05"))
return nil
}
// 实现 driver.Valuer 接口,Value 返回 json value
func (j DateTime) Value() (driver.Value, error) {
return string(j), nil
}
//实现这两个接口方法之后我们就可以直接使用这个类型了
//查询时gorm就会直接为我们转成当前类型
type ResGroups1 struct {
Id int64
Name string
CreateDate DateTime
}
var info ResGroups1
db.Table("res_groups").First(&info, 2)
//插入时我们就可以直接用字符串插入
type ResGroups1 struct {
Name string
CreateDate DateTime
}
db.Table("res_groups").Create(&ResGroups1{Name: "123", CreateDate: "2023-03-09 06:27:45"})
最后
- 自定义类型Github 仓库已经提供了date和time类型,但是我好像没找到datetime类型,所以自己尝试了下。
- 没有在实战中使用,因为我现在也适应了直接使用time.time类型
- 对于以前从PHP转go的我来说,一开始go的时间类型确实不太适应,但是慢慢的用多了之后倒是不觉得多麻烦了
- 不局限于时间类型,其他很多gorm满足不了我们使用的时候,或者使用的时候需要经常来回处理的时候我们可以尝试自定义自己的类型以加快我们的开发速度