英文:
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 theTypeassociationWhere: 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!
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论