Preloading (Eager Loading)
Preload
GORM allows eager loading relations in other SQL with Preload, for example:
Generics 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)
Traditional API
db.Preload("Orders").Find(&users)
db.Preload("Orders").Preload("Profile").Preload("Role").Find(&users)
Joins Preloading
Preload loads the association data in a separate query, Join Preload will loads association data using left join, for example:
Generics 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)
Traditional 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})Join with conditions
db.Joins("Company", DB.Where(&Company{Alive: true})).Find(&users)
Join nested model
db.Joins("Manager").Joins("Manager.Company").Find(&users)
NOTE
Join Preloadworks with one-to-one relation, e.g:has one,belongs to
Preload All
clause.Associations can work with Preload similar like Select when creating/updating, you can use it to Preload all associations, for example:
type User struct {
gorm.Model
Name string
CompanyID uint
Company Company
Role Role
Orders []Order
}
db.Preload(clause.Associations).Find(&users)clause.Associations won’t preload nested associations, but you can use it with Nested Preloading together, e.g:
db.Preload("Orders.OrderItems.Product").Preload(clause.Associations).Find(&users)Preload with conditions
GORM allows Preload associations with conditions, it works similar to Inline Conditions
db.Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users)
db.Where("state = ?", "active").Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users)
Custom Preloading SQL
You are able to custom preloading SQL by passing in func(db *gorm.DB) *gorm.DB, for example:
db.Preload("Orders", func(db *gorm.DB) *gorm.DB {
return db.Order("orders.amount DESC")
}).Find(&users)
Nested Preloading
GORM supports nested preloading, for example:
db.Preload("Orders.OrderItems.Product").Preload("CreditCard").Find(&users)
db.Preload("Orders", "state = ?", "paid").Preload("Orders.OrderItems").Find(&users)Embedded Preloading
Embedded Preloading is used for Embedded Struct, especially the
same struct. The syntax for Embedded Preloading is similar to Nested Preloading, they are divided by dot.
For example:
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)We can omit embedded part when there is no ambiguity.
type Address struct {
CountryID int
Country Country
}
type Org struct {
Address Address `gorm:"embedded"`
}
db.Preload("Address.Country")
db.Preload("Country") NOTE
Embedded Preloadonly works withbelongs torelation.
Values of other relations are the same in database, we can’t distinguish them.
评论
登录后参与评论
InfoSphere