【问题标题】:Get nested object in structure in gorm在gorm的结构中获取嵌套对象
【发布时间】:2018-01-26 11:27:50
【问题描述】:

我有两个结构:

type GoogleAccount struct {
     Id     uint64
     Token  string
}

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

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

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

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

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

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

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

现在我找到了一种解决方案 - 将 Scanner 实施到 GoogleAccount。但是输入法中的值是[]uint8。我可以假设, []uint8 可以转换为字符串,然后我可以解析这个字符串。这个字符串(保留在 db 中)看起来像 (x,x) - 其中 x - 是值。解析字符串并将值设置为对象是正确的方法吗?或者是通过 ORM 得到这个结果的方法吗?

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

【问题讨论】:

  • 您有名为IdToken 的列吗?
  • 你有没有尝试过自己解决它...请发布许多尝试或描述一些以显示努力。
  • 为什么不想为自己的数据结构创建一个单独的表呢?为什么不直接将 Google ID 和令牌放在 Client 结构中,而不是创建一个您不想要的单独实体?不要规范化你不想规范化的东西?
  • @aerokite 是的,在嵌套字段google 中代表自己一个单独的结构
  • @G_V 我只想使用 PostresSQL 的所有可能性。我创建了单独的实体,因为这个结构不仅用在这个表中。而我的决定 - 这不是非规范化。只是我正在使用新方法,得到相同的结果,但更优雅

标签: postgresql go go-gorm


【解决方案1】:

看起来你想要用你拥有的东西做两件事:(1) 更新模型,以便你拥有正确的关系绑定,(2) 如果你想获得它将读取的数据关联起来。

模型更改

Gorm 会根据结构中的属性名称和引用结构的名称自动推断关系。问题是GoogleAccount 类型的Google 属性没有关联,因为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

【讨论】:

  • 谢谢,当 GoogleAccount 是表格时它可以工作。但在我的情况下,GoogleAccount 是 Posgres CREATE TYPE GOOGLE_ACCOUNT AS ( id NUMERIC, token TEXT ); 中的 ObjectType 我不想在其他表中分隔这种类型。
  • @Kirill 我有同样的情况,但是我使用了嵌套的 JSON。但我不知道如何在带有 gorm 的 postgresql 中使用自定义类型!
【解决方案2】:

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

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

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

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
}

【讨论】:

  • 下一次,不要只是放一个指向你的仓库的链接。在此处添加实际代码。您的链接已损坏。
  • @LucioMollinedo 感谢您的评论。我添加了代码 sn-p。
猜你喜欢
  • 1970-01-01
  • 2019-12-13
  • 1970-01-01
  • 1970-01-01
  • 2015-12-06
  • 2021-10-22
  • 2013-12-07
  • 2013-10-20
  • 1970-01-01
相关资源
最近更新 更多