我在试着想办法克服这个问题.

我有一个User struct ,上面有几个字段.然而,在为补丁用户调用解码JSON对象时,缺少键会导致将值设置为*nil.对应的数据库属性是TEXT NULL类型,因此当缺少键时,结果将始终存储为NULL.

type UpdateUserDTO struct {
  ID         uuid.UUID
  FirstName  string
  LastName   string
  ImageURL  *string
}

ImageURL可以为零,但当此对象从客户端发送时:

{ firstName: "Jimmy" }

这将解码为ImageURL=nil,因为imageUrl在JSON中不存在.

我如何处理部分更新,而不是使用map[string]struct{}而不是我的DTO来判断每个字段是否存在?

推荐答案

您可以实现一个定制的json.Unmarshaler来确定该字段是被完全省略、被提供但其值为null,还是被提供了非空值.

type OptString struct {
    IsValid bool
    String  *string
}

// If a field with this type has no corresponding field in the
// incoming JSON then this method will not be invoked and the
// IsValid flag's value will remain `false`.
func (s *OptString) UnmarshalJSON(data []byte) error {
    if err := json.Unmarshal(data, &s.String); err != nil {
        return err
    }
    s.IsValid = true
    return nil
}
type UpdateUserDTO struct {
    ID        uuid.UUID
    FirstName string
    LastName  string
    ImageURL  OptString
}

https://go.dev/play/p/hvS5E46sgkD


另一种不需要自定义类型的方法是将Go字段的值设置为current数据库列的值,只需before unmarshaling即JSON.如果传入的JSON不包含匹配的字段,则json.Decoder(json.Unmarshal使用)将不会"接触"目标的字段.

dto := loadUpdateUserDTOFromDB(conn)
if err := json.Unmarshal(data, dto); err != nil {
    return err
}

https://go.dev/play/p/grJhr4P7sgQ

Go相关问答推荐

Go汇编器命名为Constants

埃拉托塞尼筛:加快交叉关闭倍数步骤

Redis:尽管数据存在,但 rdb.Pipelined 中出现redis:nil错误

如何根据中间件的请求设置上下文值?获取 go-staticcheck 问题

我应该先解锁然后再广播吗?

在golang二进制中嵌入SvelteKit

带有前导零的整数参数被 flag.IntVar 解析为八进制

如何用mpb创建两行进度条?

使用 Go 根据 /etc/shadow 文件中的散列密码验证密码

我如何使用 TOML fixtures 在使用 Go Buffalo 框架的开发环境中为我的数据库 seeder ?

在 Go 中公开公共 JWK

Go 信号处理程序不处理终端窗口关闭

go:embed 文件扩展名模式

对所有标志进行 ORing 的简短方法

Golang泛型在用作 map 元素时不起作用

如何正确为 Go 中的值设置多种类型?

如何在 docker 文件中安装 golang 包?

手动下载并放置一个 golang mod 文件

如何发送带有登录数据的 GET 请求并将 cookie 数据保存到 txt 文件?

有没有办法停止long blocking 函数?