Golang中使用GORM进行关系映射详解
Golang中使用GORM进行关系映射详解 大家好。有人知道如何在GORM查询中建立关联关系吗?我的意思是,我想通过一次查询获取所有包含关联关系的数据。我阅读了关于预加载(preload)或连接(join)方法的资料,但不太理解。
2 回复
Diego_Alberto_Gonzal:
如何在 GORM 查询中建立关联关系
Query
检索单个对象 GORM 提供了 First、Take、Last 方法来从数据库中检索单个对象,它在查询数据库时会添加 LIMIT 1 条件,并且会返回错误 ErrR
使用 Join。免责声明:我对 GORM 一无所知。只懂“原生 SQL”。只是用谷歌搜索了一下 🙂
更多关于Golang中使用GORM进行关系映射详解的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在GORM中处理关联关系查询主要有两种方式:预加载(Preload)和连接(Join)。以下是具体实现示例:
1. 预加载(Preload)方式
预加载通过额外查询加载关联数据,适合大多数场景:
// 定义模型
type User struct {
ID uint
Name string
Profile Profile
Orders []Order
}
type Profile struct {
ID uint
UserID uint
Email string
}
type Order struct {
ID uint
UserID uint
Amount float64
}
// 预加载单个关联
var user User
db.Preload("Profile").First(&user, 1)
// 这会执行两条SQL:先查用户,再查关联的Profile
// 预加载多个关联
db.Preload("Profile").Preload("Orders").First(&user, 1)
// 预加载嵌套关联
type OrderItem struct {
ID uint
OrderID uint
Product string
}
type Order struct {
ID uint
UserID uint
Amount float64
OrderItems []OrderItem
}
var user User
db.Preload("Orders.OrderItems").First(&user, 1)
// 带条件的预加载
db.Preload("Orders", "amount > ?", 100).First(&user, 1)
2. 连接(Join)方式
连接通过SQL JOIN一次性获取所有数据,适合需要过滤关联数据的场景:
// 内连接查询
var users []User
db.Joins("Profile").Find(&users)
// 生成的SQL: SELECT * FROM users INNER JOIN profiles ON users.id = profiles.user_id
// 左连接查询
db.Joins("LEFT JOIN profiles ON users.id = profiles.user_id").Find(&users)
// 带条件的连接查询
db.Joins("Profile").Where("profiles.email LIKE ?", "%@gmail.com").Find(&users)
// 多个连接
db.Joins("Profile").Joins("LEFT JOIN orders ON users.id = orders.user_id").Find(&users)
// 选择特定字段
db.Select("users.name, profiles.email").
Joins("Profile").
Where("users.id = ?", 1).
Scan(&result)
3. 关联预加载的高级用法
// 预加载所有关联
db.Preload(clause.Associations).First(&user, 1)
// 链式预加载
db.Preload("Orders", func(db *gorm.DB) *gorm.DB {
return db.Order("created_at DESC")
}).First(&user, 1)
// 使用结构体标签定义关联
type User struct {
ID uint
Name string
Profile Profile `gorm:"foreignKey:UserID"`
Orders []Order `gorm:"foreignKey:UserID"`
}
// 多对多关联预加载
type Product struct {
ID uint
Name string
Tags []Tag `gorm:"many2many:product_tags;"`
}
type Tag struct {
ID uint
Name string
}
var product Product
db.Preload("Tags").First(&product, 1)
4. 性能对比示例
// 预加载方式(N+1查询优化)
var users []User
db.Preload("Orders").Find(&users)
// 执行2条SQL:1条查用户,1条批量查所有订单
// 连接方式(单次查询)
var result []struct {
UserID uint
UserName string
OrderID uint
OrderAmount float64
}
db.Table("users").
Select("users.id as user_id, users.name as user_name, orders.id as order_id, orders.amount as order_amount").
Joins("LEFT JOIN orders ON users.id = orders.user_id").
Scan(&result)
选择预加载还是连接取决于具体需求:预加载更简单且能避免重复数据,连接则在需要基于关联表条件过滤时更高效。

