英文:
GORM query with two or more models
问题
在Gorm中,将多个模型组合以产生一个包含2个或更多模型的结构体结果的最佳方法是什么?
给定以下示例模型:
type Book struct {
gorm.Model
Title string
Description string
AuthorID uint
}
type Author struct {
gorm.Model
FirstName string
LastName string
Books []Book
}
我想创建一个查询,通过标题来查找书籍:
db.Where("title=?", "foo").Find(&books)
到目前为止没有问题,但我还想在结果中包含Author.FirstName和Author.LastName。我尝试了各种方法,但都无法实现,因为Book结构体不包含这些字段。期望的结果应该包括与该书相关的所有字段以及Author的所有字段。
我尝试使用Select()和Join()函数来指定所有所需的字段,这会生成正确的SQL语句,但生成的Book结构体仍然不包含任何Author字段。
英文:
What's the best way to produce a struct result with 2 or more models combined in Gorm?
Given these example models:
type Book struct {
gorm.Model
Title string
Description string
AuthorID uint
}
type Author struct {
gorm.Model
FirstName string
LastName string
Books []Book
}
I want to create a query to find books by Title
db.Where("title=?", "foo").Find(&books)
So far no problem, but I would also like to include Author.FirstName and Author.LastName in the result. This does not work with any method I tried, since Book struct does not include those fields. The desired result should include all fields from a matching Book plus all fields from Author related to that Book.
Tried to use Select() and Join() functions to specify all the desired fields, which produced the correct SQL statement, but the resulting Book struct still does not contain any Author fields.
答案1
得分: 1
我能够以这种方式完成你的请求。
首先,我向Book
结构体添加了Author
字段。这样,你可以将作者的信息与他的书籍一起保存。
在查询中,你需要使用Preload("Author")
让GORM也加载authors
表中的信息。这种做法被称为预加载。下面是我工作的解决方案:
package main
import (
"fmt"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
type Book struct {
gorm.Model
Title string
Description string
AuthorID uint
Author Author
}
type Author struct {
gorm.Model
FirstName string
LastName string
Books []Book
}
func main() {
dsn := "host=localhost user=postgres password=postgres dbname=postgres port=5432 sslmode=disable"
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
panic(err)
}
db.AutoMigrate(&Book{})
db.AutoMigrate(&Author{})
book1 := &Book{Title: "Go", Description: "Intro to Golang", AuthorID: 1}
book2 := &Book{Title: "GORM", Description: "Intro to GORM", AuthorID: 1}
author := &Author{FirstName: "John", LastName: "Doe", Books: []Book{*book1, *book2}}
db.Create(author)
var books []Book
db.Preload("Author").Where("title=?", "Go").Find(&books)
for _, v := range books {
fmt.Println("book 1:")
fmt.Printf("title: %q\n\n", v.Title)
fmt.Printf("author details:\n")
fmt.Printf("first name: %q\n", v.Author.FirstName)
fmt.Printf("last name: %q\n", v.Author.LastName)
}
}
希望这能帮助你理解。
英文:
I was able to accomplish your request in this way.
First, I added Author Author
field to the Book
struct. In this way, you can save the information of the author together with his books.
In the query, you've to use Preload("Auhtor")
to let GORM load also the information from the authors
table. This practice is called eager-loading. Below, you can find my working solution:
package main
import (
"fmt"
"gorm.io/driver/postgres"
"gorm.io/gorm"
)
type Book struct {
gorm.Model
Title string
Description string
AuthorID uint
Author Author
}
type Author struct {
gorm.Model
FirstName string
LastName string
Books []Book
}
func main() {
dsn := "host=localhost user=postgres password=postgres dbname=postgres port=5432 sslmode=disable"
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
if err != nil {
panic(err)
}
db.AutoMigrate(&Book{})
db.AutoMigrate(&Author{})
book1 := &Book{Title: "Go", Description: "Intro to Golang", AuthorID: 1}
book2 := &Book{Title: "GORM", Description: "Intro to GORM", AuthorID: 1}
author := &Author{FirstName: "John", LastName: "Doe", Books: []Book{*book1, *book2}}
db.Create(author)
var books []Book
db.Preload("Author").Where("title=?", "Go").Find(&books)
for _, v := range books {
fmt.Println("book 1:")
fmt.Printf("title: %q\n\n", v.Title)
fmt.Printf("author details:\n")
fmt.Printf("first name: %q\n", v.Author.FirstName)
fmt.Printf("last name: %q\n", v.Author.LastName)
}
}
Hope this helps you understand.
答案2
得分: 0
请看下面的示例,了解如何在Gorm中组合两个或多个模型来生成一个结构体。
type Driver struct {
gorm.Model
Name string
License string
Cars []Car
}
type Car struct {
gorm.Model
Year int
Make string
ModelName string
DriverID int
}
var (
drivers = []Driver{
{Name: "Shashank", License: "India123"},
{Name: "Tom", License: "India321"},
}
cars = []Car{
{Year: 2000, Make: "Toyota", ModelName: "Tundra", DriverID: 1},
{Year: 2001, Make: "Honda", ModelName: "Accord", DriverID: 1},
}
)
func GetCars(w http.ResponseWriter, r *http.Request) {
var cars []Car
db.Find(&cars)
json.NewEncoder(w).Encode(&cars)
}
// 根据id获取车辆信息,包括驾驶员姓名和驾驶证信息
func GetCar(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
var car Car
db.First(&car, params["id"])
json.NewEncoder(w).Encode(&car)
}
请注意,这不是完整的代码,只是一个参考。如果你想查看完整的代码,可以访问我的代码库:https://github.com/amshashankk/GO_Postgres_Testing/blob/main/main.go
英文:
Please look at the example below to have a look at how we can produce a struct with two or more models combined in Gorm.
type Driver struct {
gorm.Model
Name string
License string
Cars []Car
}
type Car struct {
gorm.Model
Year int
Make string
ModelName string
DriverID int
}
var (
drivers = []Driver{
{Name: "Shashank", License: "India123"},
{Name: "Tom", License: "India321"},
}
cars = []Car{
{Year: 2000, Make: "Toyota", ModelName: "Tundra", DriverID: 1},
{Year: 2001, Make: "Honda", ModelName: "Accord", DriverID: 1},
}
)
func GetCars(w http.ResponseWriter, r *http.Request) {
var cars []Car
db.Find(&cars)
json.NewEncoder(w).Encode(&cars)
}
// Getting cars with the id, where it will include name of driver & license
func GetCar(w http.ResponseWriter, r *http.Request) {
params := mux.Vars(r)
var car Car
db.First(&car, params["id"])
json.NewEncoder(w).Encode(&car)
}
Please note this is not the full code, It is basically a reference for your solution for the full code you can check my repository.
https://github.com/amshashankk/GO_Postgres_Testing/blob/main/main.go
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论