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


單條關聯查詢

先創建兩個關聯模型:

// 用戶模型
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 記錄

var user User

DB.Debug().First(&user)

這里省略 JSON 序列化輸出的過程,直接看輸出,類似這樣:

{
    "ID": 1,
    "CreatedAt": "2020-03-11T18:26:13+08:00",
    "UpdatedAt": "2020-03-11T18:28:41+08:00",
    "DeletedAt": null,
    "Username": "test",
    "Email": "text@demo.dev",
    "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 數據:

// 方式一:手動查詢關聯數據
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 幫我們封裝好了,現在可以獲取到完整的數據,類似這樣:

{
    "ID": 1,
    "CreatedAt": "2020-03-11T18:26:13+08:00",
    "UpdatedAt": "2020-03-11T18:28:41+08:00",
    "DeletedAt": null,
    "Username": "test",
    "Email": "text@demo.dev",
    "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 列表獲取對應的數據,最后整合兩部分數據。直接使用預加載就很簡單了,代碼如下:

var users []User

// 使用預加載查詢
DB.Debug().Model(&User{}).Preload("Profile").Find(&users)

輸出如下:

[
    {
        "ID": 1,
        "CreatedAt": "2020-03-11T18:26:13+08:00",
        "UpdatedAt": "2020-03-11T18:28:41+08:00",
        "DeletedAt": null,
        "Username": "test",
        "Email": "text@demo.dev",
        "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 底層使用這兩條查詢:

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官方文檔-預加載

小結

預加載在單條關聯查詢中提供了更簡潔的語法,在列表關聯查詢中不僅解決了關聯查詢 N + 1 的問題,還自動整合了數據,方便快捷。

到這里,一個簡單的預加載查詢就完成了,但是可以發現查詢輸出還有很多瑕疵,如:只查詢 User 也會帶上空值 Profile,字段名和模型定義的一樣都是首字母大寫,並且時間格式不友好。

這就衍生出了幾個問題:

  • 如何自定義輸出結構,只輸出指定字段?
  • 如何自定義字段名,並去掉空值字段?
  • 如何自定義時間格式?

下一篇將介紹如何處理查詢輸出,解決上述問題。

如發現任何問題,歡迎指正,謝謝觀看!


參考資料: Gorm官方文檔

本文出處:https://www.cnblogs.com/zhenfengxun/
本文鏈接:https://www.cnblogs.com/zhenfengxun/p/12486325.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM