GORM 在调用 Updates() 时更新空字段?
GORM updating null field when calling Updates()?
根据GORM's docs:
Updates supports update with struct or map[string]interface{}, when
updating with struct it will only update non-zero fields by default
我的数据库中已有 Service
ID abc123
的条目。我正在尝试拿一个看起来像下面的对象:
Service{
ID: "abc123",
Name: "new service name",
CreatedAt: nil,
}
并用它来更新我现有的记录。但是当我打电话时:
tx.Model(&service).Updates(service)
数据库中的 CreatedAt
值被 nil
覆盖。如何在不覆盖 CreatedAt
值的情况下更新我的数据库记录?
更新:下面是我的Service
结构
type Service struct {
ID string `gorm:"not null;type:char(32);primary_key;column:id"`
Name string `json:"name" gorm:"size:50;not null;"`
CreatedAt *time.Time
UpdatedAt time.Time
DeletedAt *time.Time `gorm:"index"`
}
我已经为我的 Service
结构尝试了两种不同的变体。另一个是 CreatedAt
的类型是 time.Time
而不是 *time.Time
。使用 *time.Time
它将用空值覆盖我的数据库中的值。使用 time.Time
它会尝试用未初始化的时间值覆盖数据库中的值并抛出错误:Error 1292: Incorrect datetime value: '0000-00-00' for column 'created_at' at row 1
结构中 time.Time
字段类型的零值或默认值是 time.Time{}
。使用 Updates
时,要么不要填充 CreatedAt
字段,要么为其分配 time.Time{}
值。
在下面的示例中,两种情况下 CreatedAt
字段都打印出默认值或零值。
package main
import (
"fmt"
"time"
)
type T struct {
CreatedAt time.Time
C int
S string
}
func main() {
fmt.Println(T{C: 1, S: "one"})
fmt.Println(T{C: 2, S: "two", CreatedAt: time.Time{}})
}
// {0001-01-01 00:00:00 +0000 UTC 1 one}
// {0001-01-01 00:00:00 +0000 UTC 2 two}
编辑:
另外,如果 CreatedAt
字段是 time.Time
类型而不是 *time.Time
.
,我不确定 CreatedAt: nil,
是如何编译的
由于您已将 Service
结构和 CreatedAt
字段类型更新为 *time.Time
,因此以下应该有效:
tx.Model(&service).Updates(Service{Name: service.Name}) // add all fields that you want to be updated.
// resulting query
// UPDATE services SET name = 'new service name' WHERE id = 'abc123';
官方 GORM 示例是 here
此外,您可以像这样省略 created_at
字段:
tx.Model(&service).Omit("created_at").Updates(service)
使用地图
https://gorm.io/docs/update.html#Updates-multiple-columns
tx.Model(&service).Updates(map[string]interface{}{"ID": "abc123", "Name": "new service name", "CreatedAt": nil})
默认情况下,gorm 不会更新默认值(零)或零值。
如果您想控制它,请使用我在下面描述的内容。
您可以使用 sql 包提供的可空类型或创建您自己的类型。
type Model struct {
Amount *sql.NullFloat64
}
// amount will not be updated
gorm.Updates(Model{Amount: nil})
// amount will be updated as a null
gorm.Updates(Model{Amount: &sql.NullFloat64{}})
// amount will be updated as a 10.50
gorm.Updates(Model{Amount: &sql.NullFloat64{Float64: 10.50, Valid: true}})
根据GORM's docs:
Updates supports update with struct or map[string]interface{}, when updating with struct it will only update non-zero fields by default
我的数据库中已有 Service
ID abc123
的条目。我正在尝试拿一个看起来像下面的对象:
Service{
ID: "abc123",
Name: "new service name",
CreatedAt: nil,
}
并用它来更新我现有的记录。但是当我打电话时:
tx.Model(&service).Updates(service)
数据库中的 CreatedAt
值被 nil
覆盖。如何在不覆盖 CreatedAt
值的情况下更新我的数据库记录?
更新:下面是我的Service
结构
type Service struct {
ID string `gorm:"not null;type:char(32);primary_key;column:id"`
Name string `json:"name" gorm:"size:50;not null;"`
CreatedAt *time.Time
UpdatedAt time.Time
DeletedAt *time.Time `gorm:"index"`
}
我已经为我的 Service
结构尝试了两种不同的变体。另一个是 CreatedAt
的类型是 time.Time
而不是 *time.Time
。使用 *time.Time
它将用空值覆盖我的数据库中的值。使用 time.Time
它会尝试用未初始化的时间值覆盖数据库中的值并抛出错误:Error 1292: Incorrect datetime value: '0000-00-00' for column 'created_at' at row 1
结构中 time.Time
字段类型的零值或默认值是 time.Time{}
。使用 Updates
时,要么不要填充 CreatedAt
字段,要么为其分配 time.Time{}
值。
在下面的示例中,两种情况下 CreatedAt
字段都打印出默认值或零值。
package main
import (
"fmt"
"time"
)
type T struct {
CreatedAt time.Time
C int
S string
}
func main() {
fmt.Println(T{C: 1, S: "one"})
fmt.Println(T{C: 2, S: "two", CreatedAt: time.Time{}})
}
// {0001-01-01 00:00:00 +0000 UTC 1 one}
// {0001-01-01 00:00:00 +0000 UTC 2 two}
编辑:
另外,如果 CreatedAt
字段是 time.Time
类型而不是 *time.Time
.
CreatedAt: nil,
是如何编译的
由于您已将 Service
结构和 CreatedAt
字段类型更新为 *time.Time
,因此以下应该有效:
tx.Model(&service).Updates(Service{Name: service.Name}) // add all fields that you want to be updated.
// resulting query
// UPDATE services SET name = 'new service name' WHERE id = 'abc123';
官方 GORM 示例是 here
此外,您可以像这样省略 created_at
字段:
tx.Model(&service).Omit("created_at").Updates(service)
使用地图 https://gorm.io/docs/update.html#Updates-multiple-columns
tx.Model(&service).Updates(map[string]interface{}{"ID": "abc123", "Name": "new service name", "CreatedAt": nil})
默认情况下,gorm 不会更新默认值(零)或零值。 如果您想控制它,请使用我在下面描述的内容。 您可以使用 sql 包提供的可空类型或创建您自己的类型。
type Model struct {
Amount *sql.NullFloat64
}
// amount will not be updated
gorm.Updates(Model{Amount: nil})
// amount will be updated as a null
gorm.Updates(Model{Amount: &sql.NullFloat64{}})
// amount will be updated as a 10.50
gorm.Updates(Model{Amount: &sql.NullFloat64{Float64: 10.50, Valid: true}})