GORM查询涉及两个或更多模型的情况。

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

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

huangapple
  • 本文由 发表于 2022年11月8日 10:27:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/74355068.html
匿名

发表评论

匿名网友

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

确定