情景介绍
使用go语言,我需要保存xxxTime的字段至数据库中,这个字段可能为空,也可能是一段时间。我采取的是统一先赋值为空,若有需要,则再进行插入(需要根据另一个字段判断是否插入)
在我的数据库中,使用的是DATETIME
类型字段,代码中,采用的是time.Time
类型(这里有几个修改)。
使用Gorm库的实现
将xxxTime字段设置为sql.NullTime
类型
在存储前,设置时
go
res := Result{
...省略...
xxxTime: sql.NullTime{
Time: time.Time{},
Valid: false,
},
...省略...
}
在存储时
go
if err := db.Table(Table1).Create(&res).Error; err != nil {
log.Error("保存数据时出错:", err)
return -1, err
}
即可保存一条null值
之后采用进行插入即可
go
currentTime := time.Now()
tmpTime := currentTime.Add(time.Duration(msgInfo.RetryIntervalMinutes) * time.Minute)
xxxTime = tmpTime.Format("2006-01-02 15:04:05")
err := db.Table(Table1).Where("id = ?", id).Update(xxxTime, xxxTime).Error
使用ENT库
使用ent库进行同样的操作,但是遇到了很多问题。
使用sql.NullTime格式
遭遇失败
首先是采取同样的方式:同样是设置格式为sql.NullTime
(此处导入的是import "entgo.io/ent/dialect/sql"
,先前版本导入的是import "database/sql"
)
同样赋值操作是
go
res := Result{
xxxTime: sql.NullTime{
Time: time.Time{},
Valid: false,
}}
保存操作为
go
SetxxxTime(res.xxxTime)
但是会在这句报错,报错内容为:无法将 'res.xxxTime' (类型 sql.NullTime) 用作类型 time.Time
如果换为"database/sql"
中的nulltime,依旧报错。无法将 'res.xxxTime' (类型 sql.NullTime) 用作类型 time.Time
。
毕竟生成的代码中,所接受的传参就是t time.Time格式而不是其他,故显然是无法sql.nullTime的的...
go
// SetxxxTime sets the "xxx" field.
func (dlsc *DeadLetterServerCreate) SetxxxTime(t time.Time) *DeadLetterServerCreate {
dlsc.mutation.SetxxxTime(t)
return dlsc
}
// SetNillablexxxTime sets the "xxx" field if the given value is not nil.
func (dlsc *DeadLetterServerCreate) SetNillablexxxTime(t *time.Time) *DeadLetterServerCreate {
if t != nil {
dlsc.SetxxxTime(*t)
}
return dlsc
}
为什么gorm可以?
而为什么gorm中可以呢?
go
func (db *DB) Create(value interface{}) (tx *DB) {
if db.CreateBatchSize > 0 {
return db.CreateInBatches(value, db.CreateBatchSize)
}
tx = db.getInstance()
tx.Statement.Dest = value
return tx.callbacks.Create().Execute(tx)
}
翻看gorm中Create的源码,发现他所接受的是interface{}接口,因此就可以了...
保存为指针类型
参考此篇文章,里面是gorm库下的解决方啊,他提供了两种方法------sql.nullTime和保存为指针。因此照猫画虎,尝试第二种方案------保存为指针。
修改相关代码如下:
xxx *time.Time `db:"xxx"`
res := Result{
xxx: nil,
}
报错同上:毕竟是指定死类型的不是接口,所以肯定不对...
无法将 'res.xxx' (类型 *time.Time) 用作类型 time.Time
采用自动生成的 SetNillablexxx
方法
在上面查看生成代码中,发现了这样一个函数
go
// SetNillablexxx sets the "xxx" field if the given value is not nil.
func (dlsc *DeadLetterServerCreate) SetNillablexxx(t *time.Time) *DeadLetterServerCreate {
if t != nil {
dlsc.Setxxx(*t)
}
return dlsc
}
他看起来就是实现了这样的功能,因此我们修改调用为这个。
go
SetNillableNextRetryTime(res.NextRetryTime).
运行后发现,可以正常保存。
完结,撒花!!
新的问题
这样可以保存NULL了,但我想真正保存时间时候,却无法保存了...
go
testTime := time.Now()
mh.Db.MainDB.UpdateOneID(id).SetNillableNextRetryTime(&testTime)
前面一直以为是格式化问题,修改了半天还是不行。。
后来我直接用这样的语句,结果都存不进去东西。
遂修改,增加错误输出:
go
mh.Db.MainDB.UpdateOneID(id).SetNillableNextRetryTime(&nextRetryTime)
结果错误是nil
,然后这时候,他就神奇的,成功了...!!
迷惑ing