使用gorm.Scopes函數(shù)實現(xiàn)復用查詢邏輯示例
引言
今天要學習的是gorm.Scopes函數(shù)的使用。該函數(shù)的作用就是復用查詢條件。
gorm Scopes是什么
在項目中,你一定會遇到過很多需要復用的查詢條件。比如常用的場景有分頁、查詢時判定數(shù)據(jù)權限等操作。
比如,我們有兩個數(shù)據(jù)資源:用戶列表和部門列表。那么,在查詢列表的時候都會涉及到分頁。當然可以在每個列表中都增加上列表相關的查詢。同時,也可以將分頁的查詢抽取出來,做成公共的函數(shù)。
那怎么將抽取出來的分頁條件在每個列表中都能復用呢?那就是使用gorm.Scopes函數(shù)。
我們先看一個使用gorm.Scopes函數(shù)使用的簡單例子,這個例子只是為了說明gorm.Scopes函數(shù)的使用。如下:
func AmountGreaterThan1000(db *gorm.DB) *gorm.DB {
return db.Where("amount > ?", 1000)
}
func PaidWithCreditCard(db *gorm.DB) *gorm.DB {
return db.Where("pay_mode_sign = ?", "C")
}
func PaidWithCod(db *gorm.DB) *gorm.DB {
return db.Where("pay_mode_sign = ?", "C")
}
func OrderStatus(status []string) func (db *gorm.DB) *gorm.DB {
return func (db *gorm.DB) *gorm.DB {
return db.Where("status IN (?)", status)
}
}
// 查找所有金額大于 1000 的信用卡訂單
db.Scopes(AmountGreaterThan1000, PaidWithCreditCard).Find(&orders)
// 查找所有金額大于 1000 的 COD 訂單
db.Scopes(AmountGreaterThan1000, PaidWithCod).Find(&orders)
// 查找所有金額大于1000 的已付款或已發(fā)貨訂單
db.Scopes(AmountGreaterThan1000, OrderStatus([]string{"paid", "shipped"})).Find(&orders)通過上述例子可以知道,前4個函數(shù)都是func (db *gorm.DB) *gorm.DB 類型的函數(shù),即輸入一個db,然后返回一個db。在該函數(shù)中的業(yè)務邏輯其實就是最常見的db.Where、db.Offset等常用的查詢條件語句而已。只不過是對這種公共的查詢語句進行了提取并進行復用而已。
然后將這樣的函數(shù)傳遞給Scopes。Scopes函數(shù)只是簡單的將func (db *gorm.DB) *gorm.DB放到Statement.scopes這個切片中。
最后,在最終執(zhí)行的時候,會循環(huán)遍歷Statement.scopes切片,依次執(zhí)行該切片中的每一個func (db *gorm.DB) *gorm.DB函數(shù)。這樣,就把提取出來的公共的查詢條件融合在一起了。
使用場景1 -- 分頁
當然,我們在查詢時最常用的就是分頁功能。那么,如何使用gorm.Scopes實現(xiàn)分頁查詢的復用呢。如下:
func Paginate(r *http.Request) func(db *gorm.DB) *gorm.DB {
return func (db *gorm.DB) *gorm.DB {
q := r.URL.Query()
page, _ := strconv.Atoi(q.Get("page"))
if page <= 0 {
page = 1
}
pageSize, _ := strconv.Atoi(q.Get("page_size"))
switch {
case pageSize > 100:
pageSize = 100
case pageSize <= 0:
pageSize = 10
}
offset := (page - 1) * pageSize
return db.Offset(offset).Limit(pageSize)
}
}
db.Scopes(Paginate(r)).Find(&users)
db.Scopes(Paginate(r)).Find(&articles)你看,先定義了一個分頁的函數(shù)Paginate函數(shù),該函數(shù)接收一個*http.Request參數(shù),然后返回一個func(db *gorm.DB) *gorm.DB的函數(shù)。因為gorm.Scopes函數(shù)只接受func(db *gorm.DB) *gorm.DB類型的函數(shù)。最后,將Paginate函數(shù)傳遞給Scopes函數(shù)即可。
使用場景2 -- 數(shù)據(jù)權限
在go-admin開源項目中,我們還發(fā)現(xiàn)了一個典型的應用,就是數(shù)據(jù)權限。在我們的系統(tǒng)中,會遇到這樣的場景:一些數(shù)據(jù)只能自己查看或操作;或者你的上級也能查看或操作;或者同部門的人員能查看或操作自己部門的數(shù)據(jù),但不能查看或操作其他部門的權限;又或者只能查看同部門的數(shù)據(jù)但不能操作同部門的數(shù)據(jù)等等。
在go-admin中,就使用了gorm.Scopes函數(shù)來統(tǒng)一使用權限查詢條件。在每個操作中,都通過Scopes函數(shù)傳入了一個Permission函數(shù)。Permissioin函數(shù)是根據(jù)不同角色擁有的權限,轉換成對應的sql語句。如下:
// DeleteAction 通用刪除動作
func DeleteAction(control dto.Control) gin.HandlerFunc {
return func(c *gin.Context) {
db, err := pkg.GetOrm(c)
...//省略了一些邏輯
//數(shù)據(jù)權限檢查
p := GetPermissionFromContext(c)
// 將Permission函數(shù)傳入Scopes函數(shù)
db = db.WithContext(c).Scopes(
Permission(object.TableName(), p),
).Where(req.GetId()).Delete(object)
...//省略了一些邏輯
// 檢查操作的行數(shù),如果操作的行數(shù)是0,說明沒有權限
if db.RowsAffected == 0 {
response.Error(c, http.StatusForbidden, nil, "無權刪除該數(shù)據(jù)")
return
}
response.OK(c, object.GetId(), "刪除成功")
c.Next()
}
}
// Permission函數(shù)的邏輯
// 根據(jù)不同 的數(shù)據(jù)范圍枚舉值,轉換成不同的Where條件
func Permission(tableName string, p *DataPermission) func(db *gorm.DB) *gorm.DB {
return func(db *gorm.DB) *gorm.DB {
if !config.ApplicationConfig.EnableDP {
return db
}
switch p.DataScope {
case "2":
return db.Where(tableName+".create_by in (select sys_user.user_id from sys_role_dept left join sys_user on sys_user.dept_id=sys_role_dept.dept_id where sys_role_dept.role_id = ?)", p.RoleId)
case "3":
return db.Where(tableName+".create_by in (SELECT user_id from sys_user where dept_id = ? )", p.DeptId)
case "4":
return db.Where(tableName+".create_by in (SELECT user_id from sys_user where sys_user.dept_id in(select dept_id from sys_dept where dept_path like ? ))", "%/"+pkg.IntToString(p.DeptId)+"/%")
case "5":
return db.Where(tableName+".create_by = ?", p.UserId)
default:
return db
}
}
}總結
gorm Scopes是一個非常強大的特性,它可以讓你復用你的邏輯,在查詢時實現(xiàn)更為復雜的查詢邏輯。在使用gorm Scope時,你需要定義一個Scope函數(shù),并在查詢時應用它。Scope函數(shù)可以被鏈式調用,并且可以接收參數(shù)。學習并掌握這個特性將會使你在編寫gorm查詢時事半功倍。
以上就是使用gorm.Scopes函數(shù)實現(xiàn)復用查詢邏輯示例的詳細內容,更多關于gorm.Scopes復用查詢邏輯的資料請關注腳本之家其它相關文章!
相關文章
Go 控制協(xié)程(goroutine)的并發(fā)數(shù)量
控制協(xié)程goroutine的并發(fā)數(shù)量是一個常見的需求,本文就來介紹一下Go 控制協(xié)程的并發(fā)數(shù)量,具有一定的參考價值,感興趣的可以了解一下2025-02-02
Go創(chuàng)建Grpc鏈接池實現(xiàn)過程詳解
這篇文章主要為大家介紹了Go創(chuàng)建Grpc鏈接池實現(xiàn)過程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-03-03
xorm根據(jù)數(shù)據(jù)庫生成go model文件的操作
這篇文章主要介紹了xorm根據(jù)數(shù)據(jù)庫生成go model文件的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12

