beego高級查詢


ORM以QuerySeter來組織查詢,每個返回QuerySeter的方法都會獲得一個新的QuerySeter對象。

基本使用方法:

1
2
3
4
5
6
7
8
o := orm.NewOrm()
 
// 獲取 QuerySeter 對象,user 為表名
qs := o.QueryTable( "user" )
 
// 也可以直接使用對象作為表名
user := new(User)
qs = o.QueryTable(user)  // 返回 QuerySeter

 

1.expr

QuerySeter中用於描述字段和sql操作符,使用簡單的expr查詢方法。

字段組合的其后順序依照表的關系,比如User表擁有Profile的外鍵,那么對User表查詢對應的Profile.Age為條件,則使用profile__Age,

注意字段的分隔符使用雙下划線__,除了描述字段,expr的尾部可以增加操作符以執行對應的sql操作。比如profile__Age__gt代表profile.Age > 18的條件查詢。

1
2
3
4
5
6
7
8
9
10
qs.Filter( "id" , 1)  // WHERE id = 1
qs.Filter( "profile__age" , 18)  // WHERE profile.age = 18
qs.Filter( "Profile__Age" , 18)  // 使用字段名和 Field 名都是允許的
qs.Filter( "profile__age" , 18)  // WHERE profile.age = 18
qs.Filter( "profile__age__gt" , 18)  // WHERE profile.age > 18
qs.Filter( "profile__age__gte" , 18)  // WHERE profile.age >= 18
qs.Filter( "profile__age__in" , 18, 20)  // WHERE profile.age IN (18, 20)
 
qs.Filter( "profile__age__in" , 18, 20).Exclude( "profile__lt" , 1000)
// WHERE profile.age IN (18, 20) AND NOT profile_id < 1000

  

2.operators

當前支持的操作符號

  • exact / iexact 等於
  • contains / icontains 包含
  • gt / gte 大於 / 大於等於
  • lt / lte 小於 / 小於等於
  • startswith / istartswith 以…起始
  • endswith / iendswith 以…結束
  • in
  • isnull

后面以i開頭的表示:不區分大小寫。

(1)exact

Filter / Exclude / Condition expr 的默認值

1
2
3
4
qs.Filter( "name" "slene" // WHERE name = 'slene'
qs.Filter( "name__exact" "slene" // WHERE name = 'slene'
// 使用 = 匹配,大小寫是否敏感取決於數據表使用的 collation
qs.Filter( "profile_id" , nil)  // WHERE profile_id IS NULL

(2)iexact

1
2
3
qs.Filter( "name__iexact" "slene" )
// WHERE name LIKE 'slene'
// 大小寫不敏感,匹配任意 'Slene' 'sLENE'

(3)contains

1
2
3
qs.Filter( "name__contains" "slene" )
// WHERE name LIKE BINARY '%slene%'
// 大小寫敏感, 匹配包含 slene 的字符

(4)icontains

1
2
3
qs.Filter( "name__icontains" "slene" )
// WHERE name LIKE '%slene%'
// 大小寫不敏感, 匹配任意 'im Slene', 'im sLENE'

(5)in

1
2
3
4
5
6
7
8
9
qs.Filter( "age__in" , 17, 18, 19, 20)
// WHERE age IN (17, 18, 19, 20)
 
 
ids:=[]int{17,18,19,20}
qs.Filter( "age__in" , ids)
// WHERE age IN (17, 18, 19, 20)
 
// 同上效果

(6)gt/gte

1
2
3
4
5
qs.Filter( "profile__age__gt" , 17)
// WHERE profile.age > 17
 
qs.Filter( "profile__age__gte" , 18)
// WHERE profile.age >= 18

(7)li/lte

1
2
3
4
5
qs.Filter( "profile__age__lt" , 17)
// WHERE profile.age < 17
 
qs.Filter( "profile__age__lte" , 18)
// WHERE profile.age <= 18

(8)startswith

1
2
3
qs.Filter( "name__startswith" "slene" )
// WHERE name LIKE BINARY 'slene%'
// 大小寫敏感, 匹配以 'slene' 起始的字符串

(9)istartwith

1
2
3
qs.Filter( "name__istartswith" "slene" )
// WHERE name LIKE 'slene%'
// 大小寫不敏感, 匹配任意以 'slene', 'Slene' 起始的字符串 

(10)endswith

1
2
3
qs.Filter( "name__endswith" "slene" )
// WHERE name LIKE BINARY '%slene'
// 大小寫敏感, 匹配以 'slene' 結束的字符串

(11)iendswith

1
2
3
qs.Filter( "name__iendswithi" "slene" )
// WHERE name LIKE '%slene'
// 大小寫不敏感, 匹配任意以 'slene', 'Slene' 結束的字符串

(12)isnull

1
2
3
4
5
6
qs.Filter( "profile__isnull" , true)
qs.Filter( "profile_id__isnull" , true)
// WHERE profile_id IS NULL
 
qs.Filter( "profile__isnull" , false)
// WHERE profile_id IS NOT NULL

  

3.高級查詢接口使用

QuerySeter是高級查詢使用的接口,下面是其中的一些方法

type QuerySeter interface {

  • Filter(string, …interface{}) QuerySeter
  • Exclude(string, …interface{}) QuerySeter
  • SetCond(*Condition) QuerySeter
  • Limit(int, …int64) QuerySeter
  • Offset(int64) QuerySeter
  • GroupBy(…string) QuerySeter
  • OrderBy(…string) QuerySeter
  • Distinct() QuerySeter
  • RelatedSel(…interface{}) QuerySeter
  • Count() (int64, error)
  • Exist() bool
  • Update(Params) (int64, error)
  • Delete() (int64, error)
  • PrepareInsert() (Inserter, error)
  • All(interface{}, …string) (int64, error)
  • One(interface{}, …string) error
  • Values(*[]Params, …string) (int64, error)
  • ValuesList(*[]ParamsList, …string) (int64, error)
  • ValuesFlat(*ParamsList, string) (int64, error)

}

每個返回QuerySeter的api調用時都會新建一個QuerySeter,不影響之前創建的。

高級查詢使用Filter和Exclude來做常用的條件查詢,囊括兩種清晰的過濾規則:包含、排除

(1)Filter

用來過濾查詢結果,起到包含條件的作用,多個Filter之間使用AND連接。

1
2
qs.Filter( "profile__isnull" , true).Filter( "name" "slene" )
// WHERE profile_id IS NULL AND name = 'slene'

(2)Exclude

用來過濾查詢結果,起到排除條件的作用。

使用NOT排除條件,多個Exclude之間使用AND連接。

1
2
qs.Exclude( "profile__isnull" , true).Filter( "name" "slene" )
// WHERE NOT profile_id IS NULL AND name = 'slene'

(3)SetCond

自定義條件表達式

1
2
3
4
5
6
7
8
9
10
cond := orm.NewCondition()
cond1 := cond.And( "profile__isnull" , false).AndNot( "status__in" , 1).Or( "profile__age__gt" , 2000)
 
qs := orm.QueryTable( "user" )
qs = qs.SetCond(cond1)
// WHERE ... AND ... AND NOT ... OR ...
 
cond2 := cond.AndCond(cond1).OrCond(cond.And( "name" "slene" ))
qs = qs.SetCond(cond2).Count()
// WHERE (... AND ... AND NOT ... OR ...) OR ( ... )

(4)Limit

限制最大返回數據行數,第二個參數可以設置為Offset

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var  DefaultRowsLimit = 1000  // ORM 默認的 limit 值為 1000
 
// 默認情況下 select 查詢的最大行數為 1000
// LIMIT 1000
 
qs.Limit(10)
// LIMIT 10
 
qs.Limit(10, 20)
// LIMIT 10 OFFSET 20 注意跟 SQL 反過來的
 
qs.Limit(-1)
// no limit
 
qs.Limit(-1, 100)
// LIMIT 18446744073709551615 OFFSET 100
// 18446744073709551615 是 1<<64 - 1 用來指定無 limit 限制 但有 offset 偏移的情況

(5)Offset

設置偏移行數

1
2
qs.Offset(20)
// LIMIT 1000 OFFSET 20

(6)GroupBy

1
2
qs.GroupBy( "id" "age" )
// GROUP BY id,age

(7)OrderBy

在expr前使用減號-表示DESC排列

1
2
3
4
5
qs.OrderBy( "id" "-profile__age" )
// ORDER BY id ASC, profile.age DESC
 
qs.OrderBy( "-profile__age" "profile" )
// ORDER BY profile.age DESC, profile_id ASC

(8)Distinct

對應sql的distinct語句,返回不重復的值

1
2
qs.Distinct()
// SELECT DISTINCT

(9)RelatedSel

關系查詢,參數使用 expr

1
2
3
4
5
6
7
8
9
10
11
12
var  DefaultRelsDepth = 5  // 默認情況下直接調用 RelatedSel 將進行最大 5 層的關系查詢
 
qs := o.QueryTable( "post" )
 
qs.RelatedSel()
// INNER JOIN user ... LEFT OUTER JOIN profile ...
 
qs.RelatedSel( "user" )
// INNER JOIN user ...
// 設置 expr 只對設置的字段進行關系查詢
 
// 對設置 null 屬性的 Field 將使用 LEFT OUTER JOIN

(10)Count

依據當前的查詢條件,返回結果行數

1
2
cnt, err := o.QueryTable( "user" ).Count()  // SELECT COUNT(*) FROM USER
fmt.Printf( "Count Num: %s, %s" , cnt, err)

(11)Exist

1
2
exist := o.QueryTable( "user" ).Filter( "UserName" "Name" ).Exist()
fmt.Printf( "Is Exist: %s" , exist)

(12)Update

依據當前查詢條件,進行批量更新操作

1
2
3
4
5
num, err := o.QueryTable( "user" ).Filter( "name" "slene" ).Update(orm.Params{
     "name" "astaxie" ,
})
fmt.Printf( "Affected Num: %s, %s" , num, err)
// SET name = "astaixe" WHERE name = "slene"

原子操作增加字段值

1
2
3
4
5
// 假設 user struct 里有一個 nums int 字段
num, err := o.QueryTable( "user" ).Update(orm.Params{
     "nums" : orm.ColValue(orm.ColAdd, 100),
})
// SET nums = nums + 100

orm.ColValue 支持以下操作

1
2
3
4
ColAdd       // 加
ColMinus     // 減
ColMultiply  // 乘
ColExcept    // 除

(13)Delete

依據當前查詢條件,進行批量刪除操作

1
2
3
num, err := o.QueryTable( "user" ).Filter( "name" "slene" ).Delete()
fmt.Printf( "Affected Num: %s, %s" , num, err)
// DELETE FROM user WHERE name = "slene"

(14)PrepareInsert

用於一次 prepare 多次 insert 插入,以提高批量插入的速度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var  users []*User
...
qs := o.QueryTable( "user" )
i, _ := qs.PrepareInsert()
for  _, user :=  range  users {
     id, err := i.Insert(user)
     if  err == nil {
         ...
     }
}
// PREPARE INSERT INTO user (`name`, ...) VALUES (?, ...)
// EXECUTE INSERT INTO user (`name`, ...) VALUES ("slene", ...)
// EXECUTE ...
// ...
i.Close()  // 別忘記關閉 statement

(15)All

返回對象的結果集對象,All的參數支持 *[]Type 和 *[]*Type 兩種形式的 slice。

1
2
3
var  users []*User
num, err := o.QueryTable( "user" ).Filter( "name" "slene" ).All(&users)
fmt.Printf( "Returned Rows Num: %s, %s" , num, err)

All / Values / ValuesList / ValuesFlat 受到 Limit 的限制,默認最大行數為 1000

可以指定返回的字段:

1
2
3
4
5
6
7
8
9
10
type  Post  struct  {
     Id      int
     Title   string
     Content string
     Status  int
}
 
// 只返回 Id 和 Title
var  posts []Post
o.QueryTable( "post" ).Filter( "Status" , 1).All(&posts,  "Id" "Title" )

對象的其它字段值將會是對應類型的默認值。

(16)one

闡述返回單條記錄

1
2
3
4
5
6
7
8
9
10
var  user User
err := o.QueryTable( "user" ).Filter( "name" "slene" ).One(&user)
if  err == orm.ErrMultiRows {
     // 多條的時候報錯
     fmt.Printf( "Returned Multi Rows Not One" )
}
if  err == orm.ErrNoRows {
     // 沒有找到記錄
     fmt.Printf( "Not row found" )
}

可以指定返回的字段。

1
2
3
// 只返回 Id 和 Title
var  post Post
o.QueryTable( "post" ).Filter( "Content__istartswith" "prefix string" ).One(&post,  "Id" "Title" )

對象的其它字段值將會是對應類型的默認值。

(17)Values

以鍵值對的方式返回結果集。key 為 Model 里的 Field name,value 的值 以 string 保存。

1
2
3
4
5
6
7
8
var  maps []orm.Params
num, err := o.QueryTable( "user" ).Values(&maps)
if  err == nil {
     fmt.Printf( "Result Nums: %d\n" , num)
     for  _, m :=  range  maps {
         fmt.Println(m[ "Id" ], m[ "Name" ])
     }
}

返回指定的 Field 數據

TODO: 暫不支持級聯查詢 RelatedSel 直接返回 Values

但可以直接指定 expr 級聯返回需要的數據

1
2
3
4
5
6
7
8
9
var  maps []orm.Params
num, err := o.QueryTable( "user" ).Values(&maps,  "id" "name" "profile" "profile__age" )
if  err == nil {
     fmt.Printf( "Result Nums: %d\n" , num)
     for  _, m :=  range  maps {
         fmt.Println(m[ "Id" ], m[ "Name" ], m[ "Profile" ], m[ "Profile__Age" ])
         // map 中的數據都是展開的,沒有復雜的嵌套
     }
}

(18)ValueList

顧名思義,返回的結果集以slice存儲

結果的排列與 Model 中定義的 Field 順序一致

返回的每個元素值以 string 保存

1
2
3
4
5
6
7
8
var  lists []orm.ParamsList
num, err := o.QueryTable( "user" ).ValuesList(&lists)
if  err == nil {
     fmt.Printf( "Result Nums: %d\n" , num)
     for  _, row :=  range  lists {
         fmt.Println(row)
     }
}

當然也可以指定 expr 返回指定的 Field

1
2
3
4
5
6
7
8
var  lists []orm.ParamsList
num, err := o.QueryTable( "user" ).ValuesList(&lists,  "name" "profile__age" )
if  err == nil {
     fmt.Printf( "Result Nums: %d\n" , num)
     for  _, row :=  range  lists {
         fmt.Printf( "Name: %s, Age: %s\m" , row[0], row[1])
     }
}

(19)ValueFlat

只返回特定的 Field 值,將結果集展開到單個 slice 里

1
2
3
4
5
6
var  list orm.ParamsList
num, err := o.QueryTable( "user" ).ValuesFlat(&list,  "name" )
if  err == nil {
     fmt.Printf( "Result Nums: %d\n" , num)
     fmt.Printf( "All User Names: %s" , strings.Join(list,  ", " ))
}

  

 

4.關系查詢

(1)User 和 Profile 是 OneToOne 的關系

已經取得了 User 對象,查詢 Profile:

1
2
3
4
5
user := &User{Id: 1}
o.Read(user)
if  user.Profile != nil {
     o.Read(<strong>user.Profile</strong>)
}

直接關聯查詢:

1
2
3
4
5
6
7
8
user := &User{}
o.QueryTable( "user" ).Filter( "Id" , 1).RelatedSel().One(user)
// 自動查詢到 Profile
fmt.Println(<strong>user.Profile</strong>)
// 因為在 Profile 里定義了反向關系的 User,所以 Profile 里的 User 也是自動賦值過的,可以直接取用。
fmt.Println(<strong>user.Profile.User</strong>)
 
// [SELECT T0.`id`, T0.`name`, T0.`profile_id`, T1.`id`, T1.`age` FROM `user` T0 INNER JOIN `profile` T1 ON T1.`id` = T0.`profile_id` WHERE T0.`id` = ? LIMIT 1000] - `1`

通過 User 反向查詢 Profile:

1
2
3
4
5
var  profile Profile
err := o.QueryTable( "profile" ).Filter( "User__Id" , 1).One(&profile)
if  err == nil {
     fmt.Println(profile)
}

  

(2)Post 和 User 是 ManyToOne 關系,也就是 ForeignKey 為 User

1
2
3
4
5
6
type  Post  struct  {
     Id    int
     Title string
     User  *User  `orm: "rel(fk)" `
     Tags  []*Tag `orm: "rel(m2m)" `
}

  

1
2
3
4
5
6
7
8
9
var  posts []*Post
num, err := o.QueryTable( "post" ).Filter( "User" , 1).RelatedSel().All(&posts)
if  err == nil {
     fmt.Printf( "%d posts read\n" , num)
     for  _, post :=  range  posts {
         fmt.Printf( "Id: %d, UserName: %d, Title: %s\n" , post.Id, post.User.UserName, post.Title)
     }
}
// [SELECT T0.`id`, T0.`title`, T0.`user_id`, T1.`id`, T1.`name`, T1.`profile_id`, T2.`id`, T2.`age` FROM `post` T0 INNER JOIN `user` T1 ON T1.`id` = T0.`user_id` INNER JOIN `profile` T2 ON T2.`id` = T1.`profile_id` WHERE T0.`user_id` = ? LIMIT 1000] - `1`

根據 Post.Title 查詢對應的 User:

RegisterModel 時,ORM 也會自動建立 User 中 Post 的反向關系,所以可以直接進行查詢

1
2
3
4
5
var  user User
err := o.QueryTable( "user" ).Filter( "Post__Title" "The Title" ).Limit(1).One(&user)
if  err == nil {
     fmt.Printf(user)
}

  

(3)Post 和 Tag 是 ManyToMany 關系

設置 rel(m2m) 以后,ORM 會自動創建中間表

1
2
3
4
5
6
7
8
9
10
11
12
type  Post  struct  {
     Id    int
     Title string
     User  *User  `orm: "rel(fk)" `
     Tags  []*Tag `orm: "rel(m2m)" `
}
 
type  Tag  struct  {
     Id    int
     Name  string
     Posts []*Post `orm: "reverse(many)" `
}

一條 Post 紀錄可能對應不同的 Tag 紀錄,一條 Tag 紀錄可能對應不同的 Post 紀錄,所以 Post 和 Tag 屬於多對多關系,通過 tag name 查詢哪些 post 使用了這個 tag

1
2
var  posts []*Post
num, err := dORM.QueryTable( "post" ).Filter( "Tags__Tag__Name" "golang" ).All(&posts)

通過 post title 查詢這個 post 有哪些 tag

1
2
var  tags []*Tag
num, err := dORM.QueryTable( "tag" ).Filter( "Posts__Post__Title" "Introduce Beego ORM" ).All(&tags)

  

5.載入關系字段

LoadRelated 用於載入模型的關系字段,包括所有的 rel/reverse - one/many 關系

ManyToMany 關系字段載入

1
2
3
4
5
6
7
8
9
// 載入相應的 Tags
post := Post{Id: 1}
err := o.Read(&post)
num, err := o.LoadRelated(&post,  "Tags" )
 
// 載入相應的 Posts
tag := Tag{Id: 1}
err := o.Read(&tag)
num, err := o.LoadRelated(&tag,  "Posts" )

User 是 Post 的 ForeignKey,對應的 ReverseMany 關系字段載入

1
2
3
4
5
6
7
8
9
10
11
12
type  User  struct  {
     Id    int
     Name  string
     Posts []*Post `orm: "reverse(many)" `
}
 
user := User{Id: 1}
err := dORM.Read(&user)
num, err := dORM.LoadRelated(&user,  "Posts" )
for  _, post :=  range  user.Posts {
     //...
}

  

6.多對多關系操作

type QueryM2Mer interface {

  • Add(…interface{}) (int64, error)
  • Remove(…interface{}) (int64, error)
  • Exist(interface{}) bool
  • Clear() (int64, error)
  • Count() (int64, error)

}

創建一個 QueryM2Mer 對象

1
2
3
4
5
6
o := orm.NewOrm()
post := Post{Id: 1}
m2m := o.QueryM2M(&post,  "Tags" )
// 第一個參數的對象,主鍵必須有值
// 第二個參數為對象需要操作的 M2M 字段
// QueryM2Mer 的 api 將作用於 Id 為 1 的 Post

  

QueryM2Mer Add

1
2
3
4
5
6
7
tag := &Tag{Name:  "golang" }
o.Insert(tag)
 
num, err := m2m.Add(tag)
if  err == nil {
     fmt.Println( "Added nums: " , num)
}

 Add 支持多種類型 Tag *Tag []*Tag []Tag []interface{} 

1
2
3
4
5
6
7
8
9
10
var  tags []*Tag
...
// 讀取 tags 以后
...
num, err := m2m.Add(tags)
if  err == nil {
     fmt.Println( "Added nums: " , num)
}
// 也可以多個作為參數傳入
// m2m.Add(tag1, tag2, tag3)

  

QueryM2Mer Remove

從M2M關系中刪除 tag

Remove 支持多種類型 Tag *Tag []*Tag []Tag []interface{}

1
2
3
4
5
6
7
8
9
10
var  tags []*Tag
...
// 讀取 tags 以后
...
num, err := m2m.Remove(tags)
if  err == nil {
     fmt.Println( "Removed nums: " , num)
}
// 也可以多個作為參數傳入
// m2m.Remove(tag1, tag2, tag3)

  

QueryM2Mer Exist

判斷 Tag 是否存在於 M2M 關系中

1
2
3
if  m2m.Exist(&Tag{Id: 2}) {
     fmt.Println( "Tag Exist" )
}

  

QueryM2Mer Clear

清除所有 M2M 關系

1
2
3
4
nums, err := m2m.Clear()
if  err == nil {
     fmt.Println( "Removed Tag Nums: " , nums)
}

  

QueryM2Mer Count

計算 Tag 的數量

1
2
3
4
nums, err := m2m.Count()
if  err == nil {
     fmt.Println( "Total Nums: " , nums)
}

 

轉自:https://www.cnblogs.com/yangmingxianshen/p/10125586.html

 


免責聲明!

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



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