(ENGLISH version)
Why gorm.DB.Updates always changes the created_at field when performing updating?
Here is a minimalist example:
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"log"
"time"
)
var Db *gorm.DB
type VModel struct {
ID uint64 `gorm:"index:id; primarykey, autoIncrement"`
CreatedAt time.Time
UpdatedAt time.Time
DeletedAt gorm.DeletedAt
}
type Archive struct {
VModel
Path string `gorm:"index:path;type:varchar(100)"`
Password string `gorm:"type:varchar(10)"`
}
func (m *Archive) Exist() (*Archive, bool) {
var existed Archive
err := Db.Model(m).Where("path = ?", m.Path).Find(&existed).Error
if err == nil && existed.Path == m.Path {
return &existed, true
}
return &existed, false
}
func (m *Archive) Update(attr *Archive) error {
updateInfo := make(map[string]interface{}, 0)
updateInfo["path"] = attr.Path
updateInfo["password"] = attr.Password
//return Db.Model(m).Select("*").Omit("created_at").Updates(updateInfo).Error
return Db.Model(m).Updates(updateInfo).Error
//return Db.Model(m).Select("path", "password").Updates(updateInfo).Error
}
func (m *Archive) Create() error {
return Db.Create(m).Error
}
func main() {
dsn := "${your-connection-string}"
Db, _ = gorm.Open(mysql.Open(dsn), &gorm.Config{})
for i := 0; i < 3; i++ {
a := &Archive{
Path: "/home/admin",
Password: "12345",
}
exist, ok := a.Exist()
if ok {
err := exist.Update(a)
if err != nil {
log.Fatalf("Update failed %s", err.Error())
}
} else {
err := a.Create()
if err != nil {
log.Fatalf("Create failed %s", err.Error())
}
}
fmt.Println("### ", i, " ### ", a.CreatedAt)
}
}
And here is the output:
### 0 ### 2023-03-13 23:15:14.232 +0800 CST
### 1 ### 0001-01-01 00:00:00 +0000 UTC
### 2 ### 0001-01-01 00:00:00 +0000 UTC
Although field created_at in database is not changed to 0001-01-01 00:00:00 +0000 UTC, the struct in the memory is obviously modified. And I find this behavior very annoying because in my situation, I wish to get some data from frontend, save them to database, and then return them to the frontend(Actually I will modify part of the data before returning them). But now every Updates operation changes the created_at field to 0001-01-01 00:00:00 +0000 UTC so it becomes a total mess at the frontend.
According to doc, I tried Db.Model(m).Select("*").Omit("created_at").Updates(updateInfo) and Db.Model(m).Select("path", "password").Updates(updateInfo), but neither works.
Of course, I can read data from database after each update, but it costs me one more interaction with database and might drag my service down when data accumulate to a huge number.
So is there a graceful way to bypass that? Or could you fix that in future releases? Thank you.
(中文版)
我看到社区既有英文提问又有中文提问所以为了方便作者解答又写了一下中文版问题
现在发现 gorm.DB.Updates 这个方法在更新数据库的时候会把 created_at 设置为 0001-01-01 00:00:00 +0000 UTC,复现过程以及输出参考上面的代码
我目前的场景是从前端接收数据,然后更新到数据库中,同时做一些计算后再将这个数据返回给前端;其中计算会用到 created_at 字段,最终的计算结果也会返回给前端展示,现在 gorm.DB.Updates 函数的奇怪行为导致前端展示的数据都是错的;当然我可以每次调用完
gorm.DB.Updates 函数接着再从数据库中读一次数据,但是这样就增加了一次和数据库的交互,对性能会有影响
另外我参考官方文档尝试了 Db.Model(m).Select("*").Omit("created_at").Updates(updateInfo) 和 Db.Model(m).Select("path", "password").Updates(updateInfo),然而都没有用,它们都会在 update 时修改内存中的结构体的 created_at 字段,把它改成 0001-01-01 00:00:00 +0000 UTC
不知道有没有更好的方法规避掉 gorm.DB.Updates 对 created_at 的修改?或者你们可以修改一下 gorm.DB.Updates 的行为吗?谢谢
Comment From: github-actions[bot]
The issue has been automatically marked as stale as it missing playground pull request link, which is important to help others understand your issue effectively and make sure the issue hasn't been fixed on latest master, checkout https://github.com/go-gorm/playground for details. it will be closed in 30 days if no further activity occurs. if you are asking question, please use the Question template, most likely your question already answered https://github.com/go-gorm/gorm/issues or described in the document https://gorm.io ✨ Search Before Asking ✨
Comment From: alresvor
更新可以看 https://gorm.io/zh_CN/docs/update.html#不使用-Hook-和时间追踪 其实就是默认的定义 https://gorm.io/zh_CN/docs/models.html 简单做法就是把 UpdatedAt 字段删掉
Comment From: github-actions[bot]
The issue has been automatically marked as stale as it missing playground pull request link, which is important to help others understand your issue effectively and make sure the issue hasn't been fixed on latest master, checkout https://github.com/go-gorm/playground for details. it will be closed in 30 days if no further activity occurs. if you are asking question, please use the Question template, most likely your question already answered https://github.com/go-gorm/gorm/issues or described in the document https://gorm.io ✨ Search Before Asking ✨
Comment From: programmerX1123
更新可以看 https://gorm.io/zh_CN/docs/update.html#不使用-Hook-和时间追踪 其实就是默认的定义 https://gorm.io/zh_CN/docs/models.html 简单做法就是把 UpdatedAt 字段删掉
你可能没明白我的问题,现在问题出在 CreatedAt 字段而不是 UpdatedAt 字段;另外我试了下你给的链接中的 UpdateColumns 方法,还是不行,依然会把 CreatedAt 修改为 0001-01-01;删除字段也不可取,因为我是在维护历史项目。。不过还是谢谢你
Comment From: github-actions[bot]
The issue has been automatically marked as stale as it missing playground pull request link, which is important to help others understand your issue effectively and make sure the issue hasn't been fixed on latest master, checkout https://github.com/go-gorm/playground for details. it will be closed in 30 days if no further activity occurs. if you are asking question, please use the Question template, most likely your question already answered https://github.com/go-gorm/gorm/issues or described in the document https://gorm.io ✨ Search Before Asking ✨
Comment From: black-06
In your case, when updating, it's exist and map that are passed to GORM, not a.
So it's not gorm modified a.CreatedAt, it was originally a zero value.
try fmt.Println(exist) after Update
Comment From: github-actions[bot]
The issue has been automatically marked as stale as it missing playground pull request link, which is important to help others understand your issue effectively and make sure the issue hasn't been fixed on latest master, checkout https://github.com/go-gorm/playground for details. it will be closed in 30 days if no further activity occurs. if you are asking question, please use the Question template, most likely your question already answered https://github.com/go-gorm/gorm/issues or described in the document https://gorm.io ✨ Search Before Asking ✨
Comment From: alresvor
2023/03/14 13:26:38 D:/Downloads/aa/main.go:30
[0.577ms] [rows:1] SELECT * FROM `archives` WHERE path = '/home/admin' AND `archives`.`deleted_at` IS NULL LIMIT 1
2023/03/14 13:26:38 D:/Downloads/aa/main.go:42
[1.863ms] [rows:1] UPDATE `archives` SET `password`='12345',`path`='/home/admin',`updated_at`='2023-03-14 05:26:38.901' WHERE `archives`.`deleted_at` IS NULL AND `id` = 2
### 0 ### 0001-01-01 00:00:00 +0000 UTC
2023/03/14 13:26:38 D:/Downloads/aa/main.go:30
[0.593ms] [rows:1] SELECT * FROM `archives` WHERE path = '/home/admin' AND `archives`.`deleted_at` IS NULL LIMIT 1
2023/03/14 13:26:38 D:/Downloads/aa/main.go:42
[1.420ms] [rows:1] UPDATE `archives` SET `password`='12345',`path`='/home/admin',`updated_at`='2023-03-14 05:26:38.906' WHERE `archives`.`deleted_at` IS NULL AND `id` = 2
### 1 ### 0001-01-01 00:00:00 +0000 UTC
2023/03/14 13:26:38 D:/Downloads/aa/main.go:30
[0.530ms] [rows:1] SELECT * FROM `archives` WHERE path = '/home/admin' AND `archives`.`deleted_at` IS NULL LIMIT 1
2023/03/14 13:26:38 D:/Downloads/aa/main.go:42
[1.117ms] [rows:1] UPDATE `archives` SET `password`='12345',`path`='/home/admin',`updated_at`='2023-03-14 05:26:38.909' WHERE `archives`.`deleted_at` IS NULL AND `id` = 2
### 2 ### 0001-01-01 00:00:00 +0000 UTC
之前是我看错了,不过输出一下日志,就明白了,CreatedAt 没有被修改 你显示 CreatedAt 错误是因为你代码写的有问题
exist, ok := a.Exist()
这句代码并没有修改 a 的值,你后面又打印 a 的值,自然是未赋值状态
Comment From: github-actions[bot]
The issue has been automatically marked as stale as it missing playground pull request link, which is important to help others understand your issue effectively and make sure the issue hasn't been fixed on latest master, checkout https://github.com/go-gorm/playground for details. it will be closed in 30 days if no further activity occurs. if you are asking question, please use the Question template, most likely your question already answered https://github.com/go-gorm/gorm/issues or described in the document https://gorm.io ✨ Search Before Asking ✨
Comment From: programmerX1123
In your case, when updating, it's
existandmapthat are passed to GORM, nota. So it's not gorm modifieda.CreatedAt, it was originally a zero value. tryfmt.Println(exist)afterUpdate
You're right. It's my fault. Thank you!
Comment From: programmerX1123
`` 2023/03/14 13:26:38 D:/Downloads/aa/main.go:30 [0.577ms] [rows:1] SELECT * FROMarchivesWHERE path = '/home/admin' ANDarchives.deleted_at` IS NULL LIMIT 12023/03/14 13:26:38 D:/Downloads/aa/main.go:42 [1.863ms] [rows:1] UPDATE
archivesSETpassword='12345',path='/home/admin',updated_at='2023-03-14 05:26:38.901' WHEREarchives.deleted_atIS NULL ANDid= 20 ### 0001-01-01 00:00:00 +0000 UTC
2023/03/14 13:26:38 D:/Downloads/aa/main.go:30 [0.593ms] [rows:1] SELECT * FROM
archivesWHERE path = '/home/admin' ANDarchives.deleted_atIS NULL LIMIT 12023/03/14 13:26:38 D:/Downloads/aa/main.go:42 [1.420ms] [rows:1] UPDATE
archivesSETpassword='12345',path='/home/admin',updated_at='2023-03-14 05:26:38.906' WHEREarchives.deleted_atIS NULL ANDid= 21 ### 0001-01-01 00:00:00 +0000 UTC
2023/03/14 13:26:38 D:/Downloads/aa/main.go:30 [0.530ms] [rows:1] SELECT * FROM
archivesWHERE path = '/home/admin' ANDarchives.deleted_atIS NULL LIMIT 12023/03/14 13:26:38 D:/Downloads/aa/main.go:42 [1.117ms] [rows:1] UPDATE
archivesSETpassword='12345',path='/home/admin',updated_at='2023-03-14 05:26:38.909' WHEREarchives.deleted_atIS NULL ANDid= 22 ### 0001-01-01 00:00:00 +0000 UTC
```
之前是我看错了,不过输出一下日志,就明白了,CreatedAt 没有被修改 你显示 CreatedAt 错误是因为你代码写的有问题
go exist, ok := a.Exist() 这句代码并没有修改 a 的值,你后面又打印 a 的值,自然是未赋值状态
是我傻了 非常感谢~