在gorm中获取结构中的嵌套对象

Get nested object in structure in gorm

我有两个结构:

type GoogleAccount struct {
     Id     uint64
     Token  string
}

它代表我自定义的 PostgreSQL 对象类型(我自己创建的):

CREATE TYPE GOOGLE_ACCOUNT AS
(
  id    NUMERIC,
  token TEXT
);

下一个结构是数据库中的 table:

type Client struct {
     IdClient       uint64          `gorm:"primary_key"`
     Name           string
     PhotoUrl       string
     ApprovalNumber uint16
     Phone          string
     Password       string
     HoursOfNotice  int8
     Google         GoogleAccount
}

我的自定义对象嵌套在 Client 类型中并命名为 google。我尝试通过下一种方式读取数据:

var users model.Client
db.First(&users)

但不幸的是我无法读取字段 google(有一个默认值)。我不想用 google_account 创建单独的 table,或者将此结构作为客户端 table 中的单独字段或将其打包为 json(创建单独的实体,因为这结构不仅在这个 table 中使用,而且我正在寻找新的方法,得到相同的结果,但更优雅)。 的任务不是简化 table 中的数据表示。我需要使对象从 postgres 到实体的正确映射

现在我找到了一个解决方案 - 对 GoogleAccount 实施扫描程序。但是输入法中的值是[]uint8。如我所料,[]uint8 可以转换为字符串,然后我可以解析该字符串。这个字符串(保存在数据库中)看起来像 (x,x) - 其中 x - 是值。解析字符串并将值设置为对象的正确方法是什么?或者是通过 ORM 得到这个结果的方法?

是否有可能将此数据作为嵌套结构对象读取?

看起来您需要用已有的东西做两件事:(1) 更新模型以便您拥有正确的关系绑定,以及 (2) 如果您需要,请使用 .Preload() 方法重新尝试让它关联读取的数据。

模型变更

Gorm 会根据结构中的属性名称和引用结构的名称自动推断关系。问题是类型 GoogleAccountGoogle 属性没有关联,因为 gorm 正在寻找 type Google struct.

您还缺少 GoogleAccount 上的外键。 ORM 如何知道哪个 GoogleAccount 与哪个 Client 相关联?您应该将 ClientId 添加到 GoogleAccount 结构定义中。

此外,我会更改您用来键入 uint 的主键,因为这是 gorm 默认的(除非您有充分的理由不使用它)

如果我是你,我会将我的结构定义更改为以下内容:

type Client struct {
     IdClient       uint            `gorm:"primary_key"`
     Name           string
     PhotoUrl       string
     ApprovalNumber uint16
     Phone          string
     Password       string
     HoursOfNotice  int8
     GoogleAccount  GoogleAccount    // Change this to `GoogleAccount`, the same name of your struct
}

type GoogleAccount struct {
     Id             uint
     ClientId       uint             // Foreign key
     Token          string
}

有关这方面的更多信息,请查看此处的协会文档:http://gorm.io/associations.html#has-one

预加载关联

现在您实际上已将它们正确关联,您可以.Preload()获得您想要的嵌套对象:

db.Preload("GoogleAccount").First(&user)

使用 .Preload() 将根据 ClientId.

使用正确关联的 GoogleAccount 填充 user.GoogleAccount 属性

有关这方面的更多信息,请查看预加载文档:http://gorm.io/crud.html#preloading-eager-loading

现在我找到了一个解决方案 - 将 Scanner 实施到 GoogleAccount。在 Scan 方法的输入中,我得到了 []uint8,最后我将其转换为字符串并解析。这个字符串(保存在数据库中)看起来像 (x,x) - 其中 x - 是值。当然,这不是实现我的目标的正确方法。但是我找不到其他解决方案。

强烈推荐通过关系使用经典绑定或简单地将这些字段保持在table中作为最简单的值(而不是对象)。

但是如果你想在table中尝试嵌套对象,你可以看看我的实现,也许它对你有用:

type Client struct {
    // many others fields
    Google          GoogleAccount   `json:"google"`
}

type GoogleAccount struct {
    Id      uint64      `json:"id"`
    Token   string      `json:"token"`
}

func (google GoogleAccount) Value() (driver.Value, error) {
    return "(" + strconv.FormatUint(google.Id, 10) + "," + google.Token + ")", nil
}

func (google *GoogleAccount) Scan(value interface{}) error {
    values := utils.GetValuesFromObject(value)
    google.Id, _ = strconv.ParseUint(values[0], 10, 64)
    google.Token = values[1]
    return nil
}