【问题标题】:GORM updating null field when calling Updates()?调用 Updates() 时 GORM 更新空字段?
【发布时间】:2022-01-06 00:42:49
【问题描述】:

根据GORM's docs

Updates 支持使用 struct 或 map[string]interface{} 进行更新,当 使用 struct 更新默认只会更新非零字段

我的数据库中已经有一个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

【问题讨论】:

  • 请提供您对type Service struct {...}的定义
  • @bambula - 更新
  • time.Time 字段的零值为time.Time{}。你试过用nil代替吗?
  • 如果CreatedAttime.Time 那么CreatedAt: nil, 将无法编译,您能否显示实际代码,它可能很重要。
  • @mkopriva - 你说得对,我更新了我的结构以反映我实际设置它的方式。

标签: go go-gorm


【解决方案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)

【讨论】:

  • 当我尝试这样做时,GORM 在更新语句中包含created_at,如下所示:UPDATE services SET ... created_at = '0001-01-01 00:00:00' ... WHERE ... 然后抛出错误:ERROR 1292 (22007): Incorrect datetime value: '0001-01-01 00:00:00' for column 'created_at' at row 1 当我尝试执行它时
  • 我已根据您对问题中Service 结构的更新更新了答案。
【解决方案2】:

默认情况下,gorm 不会更新默认值(零)或 nil 值。 如果您想控制它,请使用我在下面描述的东西。 您可以使用 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}})

【讨论】:

    【解决方案3】:

    使用地图 https://gorm.io/docs/update.html#Updates-multiple-columns

    tx.Model(&service).Updates(map[string]interface{}{"ID": "abc123", "Name": "new service name", "CreatedAt": nil})
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-05-30
      • 1970-01-01
      • 2021-11-11
      • 2010-12-24
      • 2019-11-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-15
      相关资源
      最近更新 更多