我用GORM ORM的围棋.

type Place struct {
  ID          int
  Name        string
  Town        Town
}

type Town struct {
  ID   int
  Name string
}

现在我想查询所有的地方,并与它们的所有字段一起处理相应城镇的信息. 这是我的代码:

db, _ := gorm.Open("sqlite3", "./data.db")
defer db.Close()

places := []Place{}
db.Find(&places)
fmt.Println(places)

我的示例数据库包含以下数据:

/* places table */
id  name    town_id
 1  Place1        1
 2  Place2        1

/* towns Table */
id name
 1 Town1
 2 Town2

receiving岁了:

[{1 Place1 {0 }} {2 Mares Place2 {0 }}]

但我expecting岁就会收到这样的东西(两个地方属于同一个城镇):

[{1 Place1 {1 Town1}} {2 Mares Place2 {1 Town1}}]

我怎么才能做这样的查询呢?我试着使用PreloadsRelated,但没有成功(可能用错了方法).我无法达到预期的效果.

推荐答案

必须将TownID指定为外键.Place struct 如下所示:

type Place struct {
  ID          int
  Name        string
  Description string
  TownID      int
  Town        Town
}

现在有不同的方法来处理这个问题.例如:

places := []Place{}
db.Find(&places)
for i, _ := range places {
    db.Model(places[i]).Related(&places[i].Town)
}

这当然会产生预期的结果,但请注意日志(log)输出和触发的查询.

[4.76ms]  SELECT  * FROM "places"
[1.00ms]  SELECT  * FROM "towns"  WHERE ("id" = '1')
[0.73ms]  SELECT  * FROM "towns"  WHERE ("id" = '1')

[{1 Place1  {1 Town1} 1} {2 Place2  {1 Town1} 1}]

输出是预期的,但是这种方法有一个根本的缺陷,请注意,对于每个地方都需要执行另一个数据库查询,这会产生n + 1个问题.这可以解决问题,但随着名额的增加,很快就会失控.

事实证明,使用预加载的good方法相当简单.

db.Preload("Town").Find(&places)

就是这样,生成的查询日志(log)是:

[22.24ms]  SELECT  * FROM "places"
[0.92ms]  SELECT  * FROM "towns"  WHERE ("id" in ('1'))

[{1 Place1  {1 Town1} 1} {2 Place2  {1 Town1} 1}]

这种方法只会触发两个查询,一个针对所有地点,另一个针对所有有地点的城镇.这种方法在地点和城镇数量方面具有很好的伸缩性(所有情况下只有两个查询).

Go相关问答推荐

Makefile:现有文件上没有这样的文件或目录,不加载环境变量

try 用GitHub操作中的release标签更新version. go文件,但失败了

如何在另一个文件夹中使用Delve运行二进制文件?

困扰围棋官方巡回赛的S建议所有方法都使用同一类型的接收器

在不耗尽资源的情况下处理S3文件下载

Golang在不写入磁盘的情况下为jpeg图像生成一致的哈希

日志(log)文件不在 golang 的日志(log)目录中

如何找到一个空闲的TPM句柄来保存新的密钥对对象?

3 字节切片和有符号整数类型之间的转换

当我使用 CircleCI 构建 Go Image 时,我得到runtime/cgo: pthread_create failed: Operation not allowed

当填充通道的函数调用未嵌入 goroutine 时,为什么我会遇到死锁?

如何确定作为函数参数传递的指针是否正在被修改或副本是否正在被修改?

不能使用 mockDB(*MockDB 类型的变量)作为 struct 文字中的 *gorm.DB 值

GOLANG:为什么 SetDeadline/SetReadDeadline/SetWriteDeadline 在使用 os.File.Fd() 时对文件不起作用?

如何在 Docker 容器中使用私有存储库进行身份验证

将 []float64 像素切片转换为图像

通用函数与外部包中的常见成员一起处理不同的 struct ?

Go模板中的浮点除法

无法识别同步错误.使用一次

如何使用 httputil.ReverseProxy 设置 X-Forwarded-For