Gorm Golang orm 协会 [英] Gorm Golang orm associations
问题描述
我将 Go 与 GORM ORM 一起使用.我有以下结构.关系很简单.一个镇有多个地方,一个地方属于一个镇.
I'm using Go with the GORM ORM. I have the following structs. The relation is simple. One Town has multiple Places and one Place belongs to one Town.
type Place struct {
ID int
Name string
Town Town
}
type Town struct {
ID int
Name string
}
现在我想查询所有地方并与他们的所有领域相处相应城镇的信息.这是我的代码:
Now i want to query all places and get along with all their fields the info of the corresponding town. This is my code:
db, _ := gorm.Open("sqlite3", "./data.db")
defer db.Close()
places := []Place{}
db.Find(&places)
fmt.Println(places)
我的示例数据库有以下数据:
My sample database has this data:
/* places table */
id name town_id
1 Place1 1
2 Place2 1
/* towns Table */
id name
1 Town1
2 Town2
我收到这个:
[{1 Place1 {0 }} {2 Mares Place2 {0 }}]
但我期待收到这样的东西(两个地方都属于同一个城镇):
But i'm expecting to receive something like this (both places belongs to the same town):
[{1 Place1 {1 Town1}} {2 Mares Place2 {1 Town1}}]
我怎么做这样的查询?我尝试使用 Preloads
和 Related
没有成功(可能是错误的方式).我无法获得预期的结果.
How can i do such query ? I tried using Preloads
and Related
without success (probably the wrong way). I can't get working the expected result.
推荐答案
TownID
必须指定为外键.Place
结构是这样的:
TownID
must be specified as the foreign key. The Place
struct gets like this:
type Place struct {
ID int
Name string
Description string
TownID int
Town Town
}
现在有不同的方法来处理这个问题.例如:
Now there are different approach to handle this. For example:
places := []Place{}
db.Find(&places)
for i, _ := range places {
db.Model(places[i]).Related(&places[i].Town)
}
这肯定会产生预期的结果,但请注意日志输出和触发的查询.
This will certainly produce the expected result, but notice the log output and the queries triggered.
[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}]
输出是预期的,但这种方法有一个基本缺陷,请注意,对于每个地方都需要进行另一个 db 查询,这会产生 n + 1
问题.这可以解决问题,但随着场所数量的增加,很快就会失控.
The output is the expected but this approach has a fundamental flaw, notice that for every place there is the need to do another db query which produce a n + 1
problem issue. This could solve the problem but will quickly gets out of control as the amount of places grow.
事实证明,使用预加载的好的方法相当简单.
It turns out that the good approach is fairly simple using preloads.
db.Preload("Town").Find(&places)
就是这样,产生的查询日志是:
That's it, the query log produced is:
[22.24ms] SELECT * FROM "places"
[0.92ms] SELECT * FROM "towns" WHERE ("id" in ('1'))
[{1 Place1 {1 Town1} 1} {2 Place2 {1 Town1} 1}]
这种方法只会触发两个查询,一个针对所有地点,一个针对所有拥有地点的城镇.这种方法在地方和城镇的数量方面可以很好地扩展(在所有情况下只有两个查询).
This approach will only trigger two queries, one for all places, and one for all towns that has places. This approach scales well regarding of the amount of places and towns (only two queries in all cases).
这篇关于Gorm Golang orm 协会的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!