英文:
Gorm preload m2m relation
问题
我想使用gorm预加载M2M
关系,但使用Preload
函数时,它没有填充切片。
这是SQL模式
create table project (
id int generated by default as identity,
name varchar(64) not null,
slug varchar(64) not null,
image_url text,
constraint project_pk primary key (id),
constraint project_unq unique (name, slug)
);
create table donation (
id int generated by default as identity,
user_id varchar(36) not null,
total_amount numeric(7, 2) not null,
currency varchar(3) not null,
constraint donation_pk primary key (id)
);
create table donation_detail (
donation_id int not null,
project_id int not null,
amount numeric(7, 2) not null,
primary key (donation_id, project_id)
);
这是我的gorm模型
type Donation struct {
ID uint64 `json:"id" gorm:"primarykey"`
UserID string `json:"user_id"`
PaypalOrderID string `json:"paypal_order_id"`
TotalAmount float64 `json:"total_amount"`
Currency string `json:"currency"`
DonationDetails []*DonationDetail `json:"donation_details" gorm:"many2many:donation_detail;"`
}
type Project struct {
ID uint64 `json:"id" gorm:"primarykey"`
Name string `json:"name"`
Slug string `json:"slug"`
ImageURL string `json:"image_url"`
}
type DonationDetail struct {
DonationID uint64 `json:"donation_id" gorm:"primaryKey"`
ProjectID uint64 `json:"project_id" gorm:"primaryKey"`
Amount float64 `json:"amount"`
Project Project
}
我想返回包含项目信息的捐赠和其详细信息。类似这样:
{
"id": 1,
"user_id": "e14a98d1-0c4a-45c3-b748-5ac6ba733b99",
"paypal_order_id": "6SR91505YA360210R",
"total_amount": 10000,
"currency": "EUR",
"donation_details": [
{
"donation_id": 1,
"project_id": 1,
"amount": 3000,
"project": {
"project_id": 1,
"name": "First Project",
"slug": "first_project",
"image_url": "img1.jpg"
}
},
{
"donation_id": 2,
"project_id": 2,
"amount": 7000,
"project": {
"project_id": 2,
"name": "Second Project",
"slug": "second_project",
"image_url": "img2.jpg"
}
}
]
}
我尝试使用以下代码预加载DonationDetails切片,但最终得到一个空切片:
func List(donationID string) (*Donation, error) {
var d *Donation
if err := db.Debug().Preload("DonationDetails").First(&d, donationID).Error; err != nil {
return nil, fmt.Errorf("could not list donation details: %w", err)
}
return d, nil
}
SQL调试的输出似乎打印了以下3个查询:
[rows:3] SELECT * FROM "donation_detail" WHERE "donation_detail"."donation_id" = 1
[rows:0] SELECT * FROM "donation_detail" WHERE ("donation_detail"."donation_id","donation_detail"."project_id") IN (NULL)
[rows:1] SELECT * FROM "donation" WHERE "donation"."id" = '1' ORDER BY "donation"."id" LIMIT 1
注意:我在.sql
文件中手动执行迁移,而不是使用Gorm Automigrate
功能。也许我漏掉了一些结构标签注释,或者我完全误解了它的工作原理。
PS:我只是想做类似于以下的操作:
SELECT * FROM donation d
LEFT JOIN donation_detail dd on d.id = dd.donation_id
LEFT JOIN project p on p.id = dd.project_id
使用gorm,应该如何实现这个理想的方式?肯定有人知道。我只是想做一个愚蠢的连接,这有多难呢?
英文:
i want to preload M2M
relation with gorm and it is not populating the slice with Preload
function.
This is the sql schema
create table project (
id int generated by default as identity,
name varchar(64) not null,
slug varchar(64) not null,
image_url text,
constraint project_pk primary key (id),
constraint project_unq unique (name, slug)
);
create table donation (
id int generated by default as identity,
user_id varchar(36) not null,
total_amount numeric(7, 2) not null,
currency varchar(3) not null,
constraint donation_pk primary key (id)
);
create table donation_detail (
donation_id int not null,
project_id int not null,
amount numeric(7, 2) not null,
primary key (donation_id, project_id)
);
These are my gorm models
type Donation struct {
ID uint64 `json:"id" gorm:"primarykey"`
UserID string `json:"user_id"`
PaypalOrderID string `json:"paypal_order_id"`
TotalAmount float64 `json:"total_amount"`
Currency string `json:"currency"`
DonationDetails []*DonationDetail `json:"donation_details" gorm:"many2many:donation_detail;"`
}
type Project struct {
ID uint64 `json:"id" gorm:"primarykey"`
Name string `json:"name"`
Slug string `json:"slug"`
ImageURL string `json:"image_url"`
}
type DonationDetail struct {
DonationID uint64 `json:"donation_id" gorm:"primaryKey"`
ProjectID uint64 `json:"project_id" gorm:"primaryKey"`
Amount float64 `json:"amount"`
Project Project
}
I want to return the donation and and it's details that include project information. something like this:
{
"id": 1,
"user_id": "e14a98d1-0c4a-45c3-b748-5ac6ba733b99",
"paypal_order_id": "6SR91505YA360210R",
"total_amount": 10000,
"currency": "EUR",
"donation_details": [
{
"donation_id": 1,
"project_id": 1,
"amount": 3000,
"project": {
"project_id": 1,
"name": "First Project",
"slug": "first_project",
"image_url": "img1.jpg"
}
},
{
"donation_id": 2,
"project_id": 2,
"amount": 7000,
"project": {
"project_id": 2,
"name": "Second Project",
"slug": "second_project",
"image_url": "img2.jpg"
}
}
]
}
i am trying this code to preload DonationDetails slice but it ends up being empty slice:
func List(donationID string) (*Donation, error) {
var d *Donation
if err := db.Debug().Preload("DonationDetails").First(&d, donationID).Error; err != nil {
return nil, fmt.Errorf("could not list donation details: %w", err)
}
return d, nil
}
The output of sql debug apparently prints these 3 queries:
[rows:3] SELECT * FROM "donation_detail" WHERE "donation_detail"."donation_id" = 1
[rows:0] SELECT * FROM "donation_detail" WHERE ("donation_detail"."donation_id","donation_detail"."project_id") IN (NULL)
[rows:1] SELECT * FROM "donation" WHERE "donation"."id" = '1' ORDER BY "donation"."id" LIMIT 1
Note: I am doing migrations manually in .sql
file and not using Gorm Automigrate
functionality.
Maybe i am missing some struct tag annotation or am i completely misunderstanding how this works.
PS: i am just trying to do something like this
SELECT * FROM donation d
LEFT JOIN donation_detail dd on d.id = dd.donation_id
LEFT JOIN project p on p.id = dd.project_id
What is the ideal way to do this with gorm? Someone has to know. i am just trying to do a stupid join, how hard can it be.
答案1
得分: 1
有几件事情可以尝试和修复:
你可能不需要使用many2many
属性来加载DonationDetail
片段,因为它们只能通过DonationID
加载。如果你有一个外键,你可以像这样添加它:
type Donation struct {
ID uint64 `json:"id" gorm:"primarykey"`
UserID string `json:"user_id"`
PaypalOrderID string `json:"paypal_order_id"`
TotalAmount float64 `json:"total_amount"`
Currency string `json:"currency"`
DonationDetails []*DonationDetail `json:"donation_details" gorm:"foreignKey:DonationID"`
}
在First
方法中,你不需要使用&d
,因为d
已经是一个指针。然而,为了加载Project
数据,你还需要进行预加载。
func List(donationID string) (*Donation, error) {
var d *Donation
if err := db.Debug().Preload("DonationDetails.Project").First(d, donationID).Error; err != nil {
return nil, fmt.Errorf("无法列出捐赠详情:%w", err)
}
return d, nil
}
英文:
There are a couple of things to try out and fix:
You probably don't need the many2many
attribute to load the DonationDetail
slice, since they can be loaded only with DonationID
. If you have a foreign key, you can add it like this:
type Donation struct {
ID uint64 `json:"id" gorm:"primarykey"`
UserID string `json:"user_id"`
PaypalOrderID string `json:"paypal_order_id"`
TotalAmount float64 `json:"total_amount"`
Currency string `json:"currency"`
DonationDetails []*DonationDetail `json:"donation_details" gorm:"foreignKey:DonationID"`
}
You don't need &d
in the First
method, since d
is already a pointer. However, to load the Project
data, you will need to preload as well.
func List(donationID string) (*Donation, error) {
var d *Donation
if err := db.Debug().Preload("DonationDetails.Project").First(d, donationID).Error; err != nil {
return nil, fmt.Errorf("could not list donation details: %w", err)
}
return d, nil
}
答案2
得分: 0
你可以使用Associations来实现这一点。
当你已经找到了你已经拥有的捐赠对象时,这是可以的。
var projects []Project
var donation Donation
conf.DB.First(&donation, "id = ?", donationID)
conf.DB.Model(&donation).Association("Donation").Find(&projects)
英文:
You achieve this using Associations.
This is Ok when you already found your donation object which you already had.
var projects []Project
var donation Donation
conf.DB.First(&donation, "id = ?", donationID)
conf.DB.Model(&donation).Association("Donation").Find(&projects)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论