关联
预加载 (Eager Loading)
登录后可跨设备保存划线和私人笔记登录
Preload
GORM 允许通过 Preload 在其他 SQL 中进行预加载,例如:
泛型 API
type User struct {
gorm.Model
Username string
Orders []Order
}
type Order struct {
gorm.Model
UserID uint
Price float64
}
user, err := gorm.G[User](db).Preload("Order", nil).Find(ctx)
user, err = gorm.G[User](db).Preload("Orders", func(db gorm.PreloadBuilder) error {
db.Order("orders.price DESC")
return nil
}).Find(ctx)
传统 API
db.Preload("Orders").Find(&users)
db.Preload("Orders").Preload("Profile").Preload("Role").Find(&users)
Joins 预加载
Preload 通过单独的查询加载关联数据,Join Preload 则使用左连接加载关联数据,例如:
泛型 API
type User struct {
gorm.Model
Username string
Order Order
}
type Order struct {
gorm.Model
UserID uint
Price float64
}
users, err := gorm.G[User](db).Joins(clause.JoinTarget{Association: "Order"}, nil).Find(ctx)
users, err := gorm.G[User](db).Joins(
clause.JoinTarget{Association: "Order"},
func(db gorm.JoinBuilder, joinTable clause.Table, curTable clause.Table) error {
db.Where(Order{Price: 1000})
return nil
}).Find(ctx)
传统 API
db.Joins("Company").Joins("Manager").Joins("Account").First(&user, 1)
db.Joins("Company").Joins("Manager").Joins("Account").First(&user, "users.name = ?", "jinzhu")
db.Joins("Company").Joins("Manager").Joins("Account").Find(&users, "users.id IN ?", []int{1,2,3,4,5})带条件的关联
db.Joins("Company", DB.Where(&Company{Alive: true})).Find(&users)
嵌套模型关联
db.Joins("Manager").Joins("Manager.Company").Find(&users)
注意
Join Preload适用于一对一关系,例如:has one、belongs to
预加载所有关联
clause.Associations 可以与 Preload 一起使用,类似于创建/更新时的 Select,你可以用它来 Preload 所有关联,例如:
type User struct {
gorm.Model
Name string
CompanyID uint
Company Company
Role Role
Orders []Order
}
db.Preload(clause.Associations).Find(&users)clause.Associations 不会预加载嵌套关联,但你可以与嵌套预加载一起使用,例如:
db.Preload("Orders.OrderItems.Product").Preload(clause.Associations).Find(&users)带条件的预加载
GORM 允许带条件地预加载关联,其用法类似于内联条件
db.Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users)
db.Where("state = ?", "active").Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users)
自定义预加载 SQL
你可以通过传入 func(db *gorm.DB) *gorm.DB 来自定义预加载 SQL,例如:
db.Preload("Orders", func(db *gorm.DB) *gorm.DB {
return db.Order("orders.amount DESC")
}).Find(&users)
嵌套预加载
GORM 支持嵌套预加载,例如:
db.Preload("Orders.OrderItems.Product").Preload("CreditCard").Find(&users)
db.Preload("Orders", "state = ?", "paid").Preload("Orders.OrderItems").Find(&users)内嵌预加载
内嵌预加载用于 内嵌结构体,特别是相同的结构体。内嵌预加载的语法与嵌套预加载类似,它们用点号分隔。
例如:
type Address struct {
CountryID int
Country Country
}
type Org struct {
PostalAddress Address `gorm:"embedded;embeddedPrefix:postal_address_"`
VisitingAddress Address `gorm:"embedded;embeddedPrefix:visiting_address_"`
Address struct {
ID int
Address
} `gorm:"embedded;embeddedPrefix:nested_address_"`
}
db.Preload("Address.Country")
db.Preload("PostalAddress.Country")
db.Preload("NestedAddress.Address.Country")
db.Preload(clause.Associations)当不存在歧义时,我们可以省略内嵌部分。
type Address struct {
CountryID int
Country Country
}
type Org struct {
Address Address `gorm:"embedded"`
}
db.Preload("Address.Country")
db.Preload("Country") 注意
内嵌预加载仅适用于belongs to关系。
其他关系的值在数据库中是相同的,我们无法区分它们。
评论
登录后参与评论
正在加载评论…
KnowForge