Gorm 預載入及輸出處理(一)- 預載入應用
阿新 • • 發佈:2020-03-13
## 單條關聯查詢
先建立兩個關聯模型:
```go
// 使用者模型
type User struct {
gorm.Model
Username string `gorm:"type:varchar(20);not null;unique"`
Email string `gorm:"type:varchar(64);not null;unique"`
Role string `gorm:"type:varchar(32);not null"`
Active uint8 `gorm:"type:tinyint unsigned;default:1"`
Profile Profile `gorm:"foreignkey:UserID;association_autoupdate:false"`
}
// 使用者資訊模型
type Profile struct {
gorm.Model
UserID uint `gorm:"type:int unsigned;not null;unique"`
Username string `gorm:"type:varchar(20);not null;unique"`
Nickname string `gorm:"type:varchar(64);not null;unique"`
Phone string `gorm:"type:varchar(32)"`
Gender uint8 `gorm:"type:tinyint unsigned;default:0"`
Birthday time.Time `gorm:"type:datetime;default:null"`
Sign string `gorm:"type:varchar(255)"`
Avatar string `gorm:"type:text"`
}
```
直接查詢單條 User 記錄
```go
var user User
DB.Debug().First(&user)
```
這裡省略 JSON 序列化輸出的過程,直接看輸出,類似這樣:
```json
{
"ID": 1,
"CreatedAt": "2020-03-11T18:26:13+08:00",
"UpdatedAt": "2020-03-11T18:28:41+08:00",
"DeletedAt": null,
"Username": "test",
"Email": "[email protected]",
"Role": "member",
"Active": 1,
"Profile": {
"ID": 0,
"CreatedAt": "001-01-01T00:00:00Z",
"UpdatedAt": "001-01-01T00:00:00Z",
"DeletedAt": null,
"UserID": 0,
"Username": "",
"Nickname": "",
"Phone": "",
"Gender": 0,
"Birthday": "0001-01-01T00:00:00Z",
"Sign": "",
"Avatar": ""
}
}
```
可以看到,雖然有輸出 Profile 欄位,但是裡面的欄位值全為零值,也就是說直接查詢 User 並不會預設把關聯的 Profile 一同查詢出來。
可能有童鞋要問了,沒查詢 Profile 為什麼還會輸出空值的 Profile 欄位呢?這是因為 JSON 序列化是按照模型的定義自動處理,User 模型中定義了 Profile 欄位,如進行關聯查詢且能查到結果,那麼就賦值給 Profile 欄位,否則 Profile 依然序列化輸出,只不過 Profile 裡面的欄位全都為空值。
接下來看下如何使用關聯查詢獲取完整的 User 資料:
```go
// 方式一:手動查詢關聯資料
var user User
// 第一步,查詢使用者
DB.Debug().First(&user)
// 第二步,查詢關聯的使用者資訊
// 注意,Related 方法第二個引數為 Profile 的外來鍵
DB.Debug().Model(&user).Related(&user.Profile, "UserID")
// 方式二:也可以使用預載入方式查詢關聯資料
DB.Debug().Model(&user).Preload("Profile").First(&user)
```
可以看到,使用預載入方式語法更簡練,實際上底層還是2個查詢,只不過 gorm 幫我們封裝好了,現在可以獲取到完整的資料,類似這樣:
```json
{
"ID": 1,
"CreatedAt": "2020-03-11T18:26:13+08:00",
"UpdatedAt": "2020-03-11T18:28:41+08:00",
"DeletedAt": null,
"Username": "test",
"Email": "[email protected]",
"Role": "member",
"Active": 1,
"Profile": {
"ID": 1,
"CreatedAt": "2020-03-11T18:26:13+08:00",
"UpdatedAt": "2020-03-11T18:26:13+08:00",
"DeletedAt": null,
"UserID": 1,
"Username": "test",
"Nickname": "test",
"Phone": "",
"Gender": 0,
"Birthday": "0001-01-01T00:00:00Z",
"Sign": "",
"Avatar": ""
}
}
```
## 列表關聯查詢
列表的關聯查詢和單條關聯查詢類似,不過手動進行列表的關聯查詢很繁瑣,得先查出 User 列表,然後再查詢一次 Profile 列表獲取對應的資料,最後整合兩部分資料。直接使用預載入就很簡單了,程式碼如下:
```go
var users []User
// 使用預載入查詢
DB.Debug().Model(&User{}).Preload("Profile").Find(&users)
```
輸出如下:
```json
[
{
"ID": 1,
"CreatedAt": "2020-03-11T18:26:13+08:00",
"UpdatedAt": "2020-03-11T18:28:41+08:00",
"DeletedAt": null,
"Username": "test",
"Email": "[email protected]",
"Role": "member",
"Active": 1,
"Profile": {
"ID": 1,
"CreatedAt": "2020-03-11T18:26:13+08:00",
"UpdatedAt": "2020-03-11T18:26:13+08:00",
"DeletedAt": null,
"UserID": 1,
"Username": "test",
"Nickname": "test",
"Phone": "",
"Gender": 0,
"Birthday": "0001-01-01T00:00:00Z",
"Sign": "",
"Avatar": ""
}
},
...
]
```
gorm 底層使用這兩條查詢:
```sql
SELECT * FROM `user` WHERE `user`.`deleted_at` IS NULL
SELECT * FROM `profile` WHERE `profile`.`deleted_at` IS
NULL AND ((`user_id` IN (1,2,3,4,5,6)))
```
gorm 還在內部把兩條查詢的資料都整合好了,使用相當方便。
這只是一個簡單的預載入應用,更多應用可參考 [Gorm官方文件-預載入](http://gorm.io/zh_CN/docs/preload.html)。
## 小結
預載入在單條關聯查詢中提供了更簡潔的語法,在列表關聯查詢中不僅解決了關聯查詢 N + 1 的問題,還自動整合了資料,方便快捷。
到這裡,一個簡單的預載入查詢就完成了,但是可以發現查詢輸出還有很多瑕疵,如:只查詢 User 也會帶上空值 Profile,欄位名和模型定義的一樣都是首字母大寫,並且時間格式不友好。
這就衍生出了幾個問題:
- 如何自定義輸出結構,只輸出指定欄位?
- 如何自定義欄位名,並去掉空值欄位?
- 如何自定義時間格式?
下一篇將介紹如何處理查詢輸出,解決上述問題。
如發現任何問題,歡迎指正,謝謝觀看!
-----
參考資料: [Gorm官方文件](http://gorm.io/zh_C