英文:
How to query a model where the embedded value of a relationship equals a specific value?
问题
我有两个不同的模型(cars
和types
),它们之间存在关联关系(属于关系),两者都有一个嵌入的struct
用于共同的数据(post
)。我想要检索特定的types
,但只想接收到cars
的post
值等于特定值的答案。
简而言之,根据下面的模型,我想要找到所有types
,其中cars.post.published
等于true。
模型
type Post struct {
Published bool
}
type Car struct {
gorm.Model
Brand string
Post Post `gorm:"embedded"`
}
type Type struct {
gorm.Model
Name string
CarID uint32
Car Car
Post Post `gorm:"embedded"`
}
使用db.Preload("Car").Find(&Type)
,我可以在答案对象中获取Car
的值。如果我在Car
结构上使用Where()
函数(例如Where(Car{Brand: "Volvo"}
),我可以通过brand
获取值,但是当使用Post
(例如Where(Car{Post: Post{Published: true}})
)时,它会返回所有内容。
最好的情况是,我想要使用我需要查询的主要模型作为Where()
函数的基础。例如:
q := Type{Car: Car{Post: Post{Published: true}}}
db.Preload("Car").Where(q).Find(&Type)
...但是这似乎不起作用。如何在不使用原始的SQL构建器的情况下实现这样的查询?
英文:
I have 2 different models (cars
& types
) who are related to each other (belongs-to relationship), where both have an embedded struct
for common data (post
). I want to retrieve certain types
, but only want to receive the answers where the post
value of cars
equals a certain value.
Shorty said, based on the model underneath, I want to find all types
where cars.post.published
equals true.
Models
type Post struct {
Published bool
}
type Car struct {
gorm.Model
Brand string
Post Post `gorm:"embedded"`
}
type Type struct {
gorm.Model
Name string
CarID uint32
Car Car
Post Post `gorm:"embedded"`
}
Using db.Preload("Car").Find(&Type)
I am able to get the Car
value in the answer object. If I use the Where()
function on the Car
struct (i.e. Where(Car{Brand: "Volvo"}
) I am able to get the value by brand
, but when using Post
(i.e. Where(Car{Post: Post{Published: true})
) it will just return everything.
Preferably I would like to use the main model I need to query as the base for the Where()
function. For example:
q := Type{Car: Car{Post: Post{Published: true}}}
db.Preload("Car").Where(q).Find(&Type)
... but this doesn't seem to work. How can I achieve such a query without using the raw SQL builder?
答案1
得分: 1
我能够通过以下方式解决你的问题。首先,我会分享代码,然后解释一些值得说明的要点。
package main
import (
"fmt"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
type Post struct {
Published bool
}
type Car struct {
gorm.Model
Brand string
TypeID int
Type Type
Post Post `gorm:"embedded"`
}
type Type struct {
gorm.Model
Name string
CarID int
Post Post `gorm:"embedded"`
}
func main() {
dsn := "host=localhost port=54322 user=postgres password=postgres dbname=postgres sslmode=disable"
db, err := gorm.Open(postgres.Open(dsn))
if err != nil {
panic(err)
}
db.AutoMigrate(&Car{})
db.AutoMigrate(&Type{})
// uncomment these to seed data
// db.Create(&Car{Brand: "Tesla", Type: Type{Name: "SUV", Post: Post{Published: true}}, Post: Post{Published: true}})
// db.Create(&Car{Brand: "Ford", Type: Type{Name: "City", Post: Post{Published: false}}, Post: Post{Published: false}})
var cars []Car
if err := db.Debug().Model(&Car{}).Preload("Type").Where(&Car{Post: Post{Published: true}}).Find(&cars).Error; err != nil {
panic(err)
}
for _, v := range cars {
fmt.Println(v.Type.Name)
}
}
现在,让我分享一些见解。
结构体定义
我稍微修改了它以处理这种情况。我从Type
结构体中删除了Car
字段,并在Car
结构体定义中添加了对应的字段。
设置和种子数据
然后,我通过GORM建立了与数据库的连接。我使用代码中定义的模型与数据库中的关系进行了同步。我手动添加了一些虚拟数据,仅供演示目的。
读取逻辑
然后,我运行了一个查询来获取相关数据。我使用了以下方法:
Debug
:用于记录实际的SQL语句Model
:用于指定我们要处理的关联关系Preload
:用于加载Type
关联Where
:用于指定条件(在我们的例子中,过滤条件是嵌入结构体)Find
:用于将结果映射到变量中
如果这有助于解决你的问题,请告诉我,谢谢!
英文:
I was able to manage your problem in the following way. First, I'm gonna share the code, then I'll cover the points worth explaining.
package main
import (
"fmt"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
type Post struct {
Published bool
}
type Car struct {
gorm.Model
Brand string
TypeID int
Type Type
Post Post `gorm:"embedded"`
}
type Type struct {
gorm.Model
Name string
CarID int
Post Post `gorm:"embedded"`
}
func main() {
dsn := "host=localhost port=54322 user=postgres password=postgres dbname=postgres sslmode=disable"
db, err := gorm.Open(postgres.Open(dsn))
if err != nil {
panic(err)
}
db.AutoMigrate(&Car{})
db.AutoMigrate(&Type{})
// uncomment these to seed data
// db.Create(&Car{Brand: "Tesla", Type: Type{Name: "SUV", Post: Post{Published: true}}, Post: Post{Published: true}})
// db.Create(&Car{Brand: "Ford", Type: Type{Name: "City", Post: Post{Published: false}}, Post: Post{Published: false}})
var cars []Car
if err := db.Debug().Model(&Car{}).Preload("Type").Where(&Car{Post: Post{Published: true}}).Find(&cars).Error; err != nil {
panic(err)
}
for _, v := range cars {
fmt.Println(v.Type.Name)
}
}
Now, let me share some insights.
The structs definition
I slightly changed it to handle the scenario. I removed the Car
field from the Type
struct and added its counterpart in the Car
struct definition.
Set up & seed
Then, I set up the DB connection via GORM. I synchronized the models defined in the code with the relations present in the DB. I manually seeded some dummy data just for the sake of the demo.
The reading logic
Then, I run a query to fetch the relevant data. I used the following methods:
Debug
: used to log the actual SQL statementsModel
: used to specify which relations we're going to work onPreload
: used to load theType
associationWhere
: used to specify the criteria (in our case the filter is on the embedded struct)Find
: used to map the result on a variable
Let me know if this helps solve your issue, thanks!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论