1. 程式人生 > >Gorm 預載入及輸出處理(一)- 預載入應用

Gorm 預載入及輸出處理(一)- 預載入應用

## 單條關聯查詢 先建立兩個關聯模型: ```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