# 預加載
## 預加載
GORM 允許在 `Preload` 的其它 SQL 中直接加載關系,例如:
```go
type User struct {
gorm.Model
Username string
Orders []Order
}
type Order struct {
gorm.Model
UserID uint
Price float64
}
// 查找 user 時預加載相關 Order
db.Preload("Orders").Find(&users)
// SELECT * FROM users;
// SELECT * FROM orders WHERE user_id IN (1,2,3,4);
db.Preload("Orders").Preload("Profile").Preload("Role").Find(&users)
// SELECT * FROM users;
// SELECT * FROM orders WHERE user_id IN (1,2,3,4); // has many
// SELECT * FROM profiles WHERE user_id IN (1,2,3,4); // has one
// SELECT * FROM roles WHERE id IN (4,5,6); // belongs to
```
## Joins 預加載
`Preload` 在一個單獨查詢中加載關聯數據。而 `Join Preload` 會使用 inner join 加載關聯數據,例如:
```go
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 Preload` 適用于一對一的關系,例如: `has one`, `belongs to`
## 預加載全部
與創建、更新時使用 `Select` 類似,`clause.Associations` 也可以和 `Preload` 一起使用,它可以用來 `預加載` 全部關聯,例如:
```go
type User struct {
gorm.Model
Name string
CompanyID uint
Company Company
Role Role
}
db.Preload(clause.Associations).Find(&users)
```
## 帶條件的預加載
GORM 允許帶條件的 Preload 關聯,類似于[內聯條件](../CRUD接口/query.md#inline_conditions)
```go
// 帶條件的預加載 Order
db.Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users)
// SELECT * FROM users;
// SELECT * FROM orders WHERE user_id IN (1,2,3,4) AND state NOT IN ('cancelled');
db.Where("state = ?", "active").Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users)
// SELECT * FROM users WHERE state = 'active';
// SELECT * FROM orders WHERE user_id IN (1,2) AND state NOT IN ('cancelled');
```
## 自定義預加載 SQL
您可以通過 `func(db *gorm.DB) *gorm.DB` 實現自定義預加載 SQL,例如:
```go
db.Preload("Orders", func(db *gorm.DB) *gorm.DB {
return db.Order("orders.amount DESC")
}).Find(&users)
// SELECT * FROM users;
// SELECT * FROM orders WHERE user_id IN (1,2,3,4) order by orders.amount DESC;
```
## 嵌套預加載
GORM 支持嵌套預加載,例如:
```go
db.Preload("Orders.OrderItems.Product").Preload("CreditCard").Find(&users)
// 自定義預加載 `Orders` 的條件
// 這樣,GORM 就不會加載不匹配的 order 記錄
db.Preload("Orders", "state = ?", "paid").Preload("Orders.OrderItems").Find(&users)
```