sql - Gorm 预载 m2m 关系
问题描述
我想预加载M2M
与gorm的关系,它没有用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 debug 的输出显然打印了这 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做到这一点的理想方法是什么?必须有人知道。我只是想做一个愚蠢的加入,这有多难。
解决方案
有几件事需要尝试和修复:
您可能不需要该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"`
}
您不需要&d
在First
方法中,因为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("could not list donation details: %w", err)
}
return d, nil
}
推荐阅读
- netsuite - NetSuite 保存的搜索可计算金额范围内的发票
- python - 尝试安装 discord.py 时出错 - “无法为使用 PEP 517 且无法直接安装的 multidict、yarl 构建轮子”
- javascript - 如何从 React 中的不同类访问状态值?
- delphi - 如何在 Delphi 中刷新 TDBGrid 以显示新记录?
- docker - 如何将 pod/容器创建时间戳标签添加到 kubernetes docker 容器标签?
- android - 检查 NavDestination 是否代表 DialogFragment
- sql - SQL 查询根据类型获取 SQL Server 数据库中的系统函数计数
- kubernetes - Minikube 中的存储空间是如何分配的?
- pdf - Wireshark - pdf 源到实际 pdf
- r - 如何在R中将多列绘制成条形图