子兮子兮 子兮子兮

No can, but will.

目录
GORM 读取别名字段(非表结构字段)值的方法
/      

GORM 读取别名字段(非表结构字段)值的方法

记录一下之前在 Stack Overflow链滴社区 提过的一个问题。

问题是查询结果中包含了表中不存在的一个别名字段,如何将这个非表结构字段的查询结果通过 GORM 读取到表对应的模型结构体中?

表结构是这样的

DROP TABLE IF EXISTS "test"."test";
CREATE TABLE "test"."test" (
  "id" varchar(32) NOT NULL,
  "name" varchar(255) COLLATE "pg_catalog"."default",
  "remark" varchar(255) COLLATE "pg_catalog"."default"
);
ALTER TABLE "test"."test" ADD CONSTRAINT "test_pkey" PRIMARY KEY ("id");

表对应模型结构体是这户事儿的

type Test struct {
	ID     string `gorm:"column:id;type:varchar(32);primaryKey;comment:唯一 ID,流水号" json:"id"` // 唯一 ID,流水号
	Name   string `gorm:"column:name;type:varchar(255);comment:名称" json:"name"`              // 名称
	Remark string `gorm:"column:remark;type:varchar(255);comment:备注" json:"remark"`          // 备注

	MoreInfo string `gorm:"-" json:"moreInfo"` // 更多信息,非表结构字段
}

GORM 查询代码

test := Test{ID: "0000000001"}
gormDB.Select("*, 'testMoreInfoVal' AS more_Info").Where(&test).Find(&test)

好吧,当时刚入门 Go 开发一段时间,也是刚开始用 GORM 不久,现在回过来看看我这个问题提的确实是有点蠢了。

🗨 哇哦,转眼都 7 个月过去了,马上都要 2022 年了,真的又是瞎忙的一年呢。

解决方案

有两种解决方案,回复原文是这样耐心告诉我的:

If the table structure is set and you aren't using AutoMigrate then this is solved by just changing your tags to make MoreInfo a read-only field and making sure you use the alias more_info to match the way GORM does DB -> Go naming translation.

type Test struct {
	ID     string `gorm:"column:id;type:varchar(32);primaryKey;comment:唯一 ID,流水号" json:"id"` // 唯一 ID,流水号
	Name   string `gorm:"column:name;type:varchar(255);comment:名称" json:"name"`              // 名称
	Remark string `gorm:"column:remark;type:varchar(255);comment:备注" json:"remark"`          // 备注

	MoreInfo string `gorm:"->" json:"moreInfo"` // 更多信息,非表结构字段
}

If you are using AutoMigration then the problem will be that a more_info column will be created in your table, though GORM will prevent writing to that column when using the struct.

What you could do in that case is use a new struct which embeds the Test struct like so:

type Test struct {
	ID     string `gorm:"column:id;type:varchar(32);primaryKey;comment:唯一 ID,流水号" json:"id"` // 唯一 ID,流水号
	Name   string `gorm:"column:name;type:varchar(255);comment:名称" json:"name"`              // 名称
	Remark string `gorm:"column:remark;type:varchar(255);comment:备注" json:"remark"`          // 备注

	MoreInfo string `gorm:"->" json:"moreInfo"` // 更多信息,非表结构字段
}

type TestExt struct {
	Test

	MoreInfo string `gorm:"->" json:"moreInfo"` // 更多信息
}

testext := TestExt{}
gormDB.Model(&Test{}).Select("*, 'testMoreInfoVal' AS more_info").
	Where(Test{ID: "0000000001"}).Find(&testext)

等了几个小时,等待过程中去忙别的事了,也确实没想到解决方案,得到答案的时候很感动,真的特别感谢这位大佬的回复。

方案一

意思是说,如果没有使用 GORM 的自动迁移,可以把结构体中 MoreInfo 字段的 gorm 标签改成 ->,告诉 GORM 这是一个只读字段,就能够把查询结果中的字段值读取到模型结构体中。

🗨 我当时真的是脑子抽筋了,为什么要把 gorm 标签设置成忽略这个字段呢 🤦‍。

方案二

如果这个模型结构体使用了 GORM 的自动迁移,那就再新加一个不自动迁移的扩展信息结构体就是了。

然后原结构体只保留表结构中存在的字段,将原结构体嵌入到扩展结构体,再将表结构中不存在的别名字段添加到扩展信息结构体中,gorm 标签还是设置成只读权限。

这样在使用 GORM 时,将 Model 设置成原结构体 &Test{},查询结果接收器设置为扩展信息结构体 &TestExt{},就可以完美解决啦,即不影响原结构体的自动迁移,也可以正常读取到别名字段的值。

总结

如果有遇到同样问题的老伙计,这里推荐使用方案二,可以避免污染原模型结构体。

因为我确实不需要使用 GORM 的自动迁移,所以我当时选择了方案一,毕竟一行代码能解决的事情,就不要用 10 行代码去解决,多写多错,少写少错,是吧。🤣

另外,告诉你一个小秘密,在 Stack Overflow 提 Golang 的 GORM 问题时,不要把标签设置成 gorm,要设置成 go-gorm,不信你试试。

2021 年 12 月 25 日,看把我闲的,女朋友今天不在,我都开始炒冷饭了,还是一个人发布于 https://zixizixi.cn/golang-gorm-reads-value-of-the-alias-field