如何查询一个模型,其中关系的嵌入值等于特定值?

huangapple go评论88阅读模式
英文:

How to query a model where the embedded value of a relationship equals a specific value?

问题

我有两个不同的模型(carstypes),它们之间存在关联关系(属于关系),两者都有一个嵌入的struct用于共同的数据(post)。我想要检索特定的types,但只想接收到carspost值等于特定值的答案。

简而言之,根据下面的模型,我想要找到所有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建立了与数据库的连接。我使用代码中定义的模型与数据库中的关系进行了同步。我手动添加了一些虚拟数据,仅供演示目的。

读取逻辑

然后,我运行了一个查询来获取相关数据。我使用了以下方法:

  1. Debug:用于记录实际的SQL语句
  2. Model:用于指定我们要处理的关联关系
  3. Preload:用于加载Type关联
  4. Where:用于指定条件(在我们的例子中,过滤条件是嵌入结构体)
  5. 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:

  1. Debug: used to log the actual SQL statements
  2. Model: used to specify which relations we're going to work on
  3. Preload: used to load the Type association
  4. Where: used to specify the criteria (in our case the filter is on the embedded struct)
  5. Find: used to map the result on a variable

Let me know if this helps solve your issue, thanks!

huangapple
  • 本文由 发表于 2023年6月7日 17:46:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/76421974.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定