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}})