GORM 在调用 Updates() 时更新 null 字段?

Abe*_*ler 5 go go-gorm

根据GORM 的文档

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

我的数据库中已有一个ServiceID 为 的条目abc123。我正在尝试获取一个如下所示的对象:

Service{
  ID: "abc123",
  Name: "new service name",
  CreatedAt: nil,
}
Run Code Online (Sandbox Code Playgroud)

并用它来更新我现有的记录。但是当我打电话时:

tx.Model(&service).Updates(service)
Run Code Online (Sandbox Code Playgroud)

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"`
}
Run Code Online (Sandbox Code Playgroud)

我已经为我的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

Emi*_*vic 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} 
Run Code Online (Sandbox Code Playgroud)

编辑: 另外,我不确定CreatedAt: nil,如果该CreatedAt字段是time.Time类型而不是*time.Time.

由于您已将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';
Run Code Online (Sandbox Code Playgroud)

官方 GORM 示例在这里

此外,您可以省略该created_at字段,如下所示:

tx.Model(&service).Omit("created_at").Updates(service)
Run Code Online (Sandbox Code Playgroud)