李林超博客
首页
归档
留言
友链
动态
关于
归档
留言
友链
动态
关于
首页
GO
正文
09.Beego框架ORM高级查询
Leefs
2022-08-05 PM
1663℃
0条
[TOC] ### 前言 ORM 以 **QuerySeter** 来组织查询,每个返回 **QuerySeter** 的方法都会获得一个新的 **QuerySeter** 对象。 ### 一、基本使用 ```go o := orm.NewOrm() // 获取 QuerySeter 对象,user 为表名 qs := o.QueryTable("user") // 也可以直接使用 Model 结构体作为表名 qs = o.QueryTable(&User) // 也可以直接使用对象作为表名 user := new(User) qs = o.QueryTable(user) // 返回 QuerySeter ``` **说明** + `QueryTable("user")` : 返回 `user`表的QuerySeter 对象。ORM 以 QuerySeter 来组织查询,每个返回 QuerySeter 的方法都会获得一个新的 QuerySeter 对象; ### 二、expr QuerySeter 中用于描述字段和 sql 操作符,使用简单的 expr 查询方法 字段组合的前后顺序依照表的关系,比如 User 表拥有 Profile 的外键,那么对 User 表查询对应的 Profile.Age 为条件,则使用 `Profile__Age` 注意,字段的分隔符号使用双下划线 `__`,除了描述字段, expr 的尾部可以增加操作符以执行对应的 sql 操作。比如 `Profile__Age__gt` 代表 Profile.Age > 18 的条件查询。 注释后面将描述对应的 sql 语句,仅仅是描述 expr 的类似结果,并不代表实际生成的语句。 ```go 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__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 ``` ### 三、Operators **当前支持的操作符号:** | 操作符 | 说明 | 举例 | | ---------------------- | -------------- | ------------------------------------------- | | exact/iexact | 等于 | where name = "Leefs" | | contains/icontains | 包含 | where name like "%Leefs%" | | gt/gte | 大于/大于等于 | where age > 20 | | lt/lte | 小于/小于等于 | where age < 20 | | startswith/istartswith | 以…起始 | where name like "Leefs%" | | endswith/iendswith | 以…结束 | where name like "%Leefs" | | in | 在什么范围里面 | where age in (1,2,3) | | isnull | 是否为空 | qs.Filter("gender__isnull",true).One(&user) | *后面以 `i` 开头的表示:大小写不敏感* #### exact `Filter / Exclude / Condition expr` 的默认值 ```go qs.Filter("name", "Leefs") // WHERE name = 'Leefs' qs.Filter("name__exact", "Leefs") // WHERE name = 'Leefs' // 使用 = 匹配,大小写是否敏感取决于数据表使用的 collation qs.Filter("id", nil) // WHERE id IS NULL ``` #### iexact ```go qs.Filter("name__iexact", "leefs") // WHERE name LIKE 'leefs' // 大小写不敏感,匹配任意 'Leefs' 'lEEFS' ``` #### contains ```go qs.Filter("name__contains", "Leefs") // WHERE name LIKE BINARY '%Leefs%' // 大小写敏感, 匹配包含 Leefs 的字符 ``` #### icontains ```go qs.Filter("name__icontains", "Leefs") // WHERE name LIKE '%Leefs%' // 大小写不敏感, 匹配任意 'im Leefs', 'im lEEFS' ``` #### in ```go 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) // 同上效果 ``` #### gt / gte ```go qs.Filter("profile__age__gt", 17) // WHERE profile.age > 17 qs.Filter("profile__age__gte", 18) // WHERE profile.age >= 18 ``` #### lt / lte ```go qs.Filter("profile__age__lt", 17) // WHERE profile.age < 17 qs.Filter("profile__age__lte", 18) // WHERE profile.age <= 18 ``` #### startswith ```go qs.Filter("name__startswith", "Leefs") // WHERE name LIKE BINARY 'Leefs%' // 大小写敏感, 匹配以 'Leefs' 起始的字符串 ``` #### istartswith ```go qs.Filter("name__istartswith", "Leefs") // WHERE name LIKE 'Leefs%' // 大小写不敏感, 匹配任意以 'Leefs', 'leefs' 起始的字符串 ``` #### endswith ```go qs.Filter("name__endswith", "Leefs") // WHERE name LIKE BINARY '%Leefs' // 大小写敏感, 匹配以 'Leefs' 结束的字符串 ``` #### iendswith ```go qs.Filter("name__iendswithi", "Leefs") // WHERE name LIKE '%Leefs' // 大小写不敏感, 匹配任意以 'Leefs', 'leefs' 结束的字符串 ``` #### isnull ```go 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 ``` ### 四、高级查询接口使用 #### Filter 用来过滤查询结果,起到 **包含条件** 的作用 多个 Filter 之间使用 `AND` 连接 ```go qs.Filter("profile__isnull", true).Filter("name", "Leefs") // WHERE profile_id IS NULL AND name = 'Leefs' ``` #### Exclude 用来过滤查询结果,起到 **排除条件** 的作用 使用 `NOT` 排除条件 多个 Exclude 之间使用 `AND` 连接 ```go qs.Exclude("profile__isnull", true).Filter("name", "Leefs") // WHERE NOT profile_id IS NULL AND name = 'Leefs' ``` #### SetCond 自定义条件表达式 ```go 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", "Leefs")) qs = qs.SetCond(cond2).Count() // WHERE (... AND ... AND NOT ... OR ...) OR ( ... ) ``` #### Limit 限制最大返回数据行数,第二个参数可以设置 `Offset` ```go 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 偏移的情况 ``` #### Offset 设置 偏移行数 ```go qs.Offset(20) // LIMIT 1000 OFFSET 20 ``` #### GroupBy ```go qs.GroupBy("id", "age") // GROUP BY id,age ``` #### OrderBy 参数使用 **expr** 在 expr 前使用减号 `-` 表示 `DESC` 的排列 ```go 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 ``` #### ForceIndex 强迫走索引。使用该选选项请确认数据库支持该特性。 ```go qs.ForceIndex(`idx_name1`,`idx_name2`) ``` #### UseIndex 使用索引。使用该特性的时候需要确认数据库是否支持该特性,以及该特性的具体含义。例如,部分数据库对于该选项是当成一种建议来执行的。 即便用户使用了`UseIndex`方法,但是数据库在具体执行的时候,也可能不会使用设定的索引。 ```go qs.UseIndex(`idx_name1`,`idx_name2`) ``` #### IgnoreIndex 忽略索引。请确认数据是否支持该选项。 ```go qs.IgnoreIndex(`idx_name1`,`idx_name2`) ``` #### Distinct 对应 sql 的 `distinct` 语句, 返回指定字段不重复的值. ```go qs.Distinct() // SELECT DISTINCT ``` #### RelatedSel 关系查询,参数使用 **expr** ```go 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 ``` #### Count 依据当前的查询条件,返回结果行数 ```go cnt, err := o.QueryTable("user").Count() // SELECT COUNT(*) FROM USER fmt.Printf("Count Num: %s, %s", cnt, err) ``` #### Exist ```go exist := o.QueryTable("user").Filter("UserName", "Name").Exist() fmt.Printf("Is Exist: %s", exist) ``` #### Update 依据当前查询条件,进行批量更新操作 ```go num, err := o.QueryTable("user").Filter("name", "Leefs").Update(orm.Params{ "name": "Leefs2", }) fmt.Printf("Affected Num: %s, %s", num, err) // SET name = "Leefs2" WHERE name = "Leefs" ``` 原子操作增加字段值 ```go // 假设 user struct 里有一个 nums int 字段 num, err := o.QueryTable("user").Update(orm.Params{ "nums": orm.ColValue(orm.ColAdd, 100), }) // SET nums = nums + 100 ``` orm.ColValue 支持以下操作 ```go ColAdd // 加 ColMinus // 减 ColMultiply // 乘 ColExcept // 除 ``` #### Delete 依据当前查询条件,进行批量删除操作 ```go num, err := o.QueryTable("user").Filter("name", "Leefs").Delete() fmt.Printf("Affected Num: %s, %s", num, err) // DELETE FROM user WHERE name = "Leefs" ``` #### PrepareInsert 用于一次 prepare 多次 insert 插入,以提高批量插入的速度。 ```go 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 ("Leefs", ...) // EXECUTE ... // ... i.Close() // 别忘记关闭 statement ``` All / Values / ValuesList / ValuesFlat 受到 Limit 的限制,默认最大行数为 1000 可以指定返回的字段: ```go 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") ``` 对象的其他字段值将会是对应类型的默认值 #### One 尝试返回单条记录 ```go var user User err := o.QueryTable("user").Filter("name", "Leefs").One(&user) if err == orm.ErrMultiRows { // 多条的时候报错 fmt.Printf("Returned Multi Rows Not One") } if err == orm.ErrNoRows { // 没有找到记录 fmt.Printf("Not row found") } ``` 可以指定返回的字段: ```go // 只返回 Id 和 Title var post Post o.QueryTable("post").Filter("Content__istartswith", "prefix string").One(&post, "Id", "Title") ``` 对象的其他字段值将会是对应类型的默认值 #### Values 返回结果集的 `key => value` 值 key 为Model里的Field name, value的值是interface{}类型,例如,如果你要将value赋值给struct中的某字段,需要根据结构体对应字段类型使用断言获取真实值。举例:`Name : m["Name"].(string)` ```go 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 级联返回需要的数据 ```go 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 中的数据都是展开的,没有复杂的嵌套 } } ``` #### ValuesList 顾名思义,返回的结果集以slice存储 结果的排列与 Model 中定义的 Field 顺序一致 返回的每个元素值以 string 保存 ```go 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 ```go 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]) } } ``` #### ValuesFlat 只返回特定的 Field 值,将结果集展开到单个 slice 里 ```go 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, ", ")) } ``` *附原文链接地址* *https://www.bookstack.cn/read/beego-2.0-zh/mvc-model-query.md*
标签:
Beego
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:
https://lilinchao.com/archives/2297.html
上一篇
08.Beego框架ORM介绍
下一篇
10.Beego框架ORM原生SQL查询
评论已关闭
栏目分类
随笔
2
Java
326
大数据
229
工具
31
其它
25
GO
47
NLP
4
标签云
高并发
Nacos
设计模式
Shiro
nginx
Docker
Spark RDD
前端
CentOS
国产数据库改造
Livy
容器深入研究
Filter
LeetCode刷题
MyBatis
Flume
Thymeleaf
Eclipse
Stream流
SQL练习题
字符串
Typora
Git
Flink
Elastisearch
JVM
Redis
NIO
链表
稀疏数组
友情链接
申请
范明明
庄严博客
Mx
陶小桃Blog
虫洞
评论已关闭