前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Golang 语言 Web 框架 beego v2 之读操作

Golang 语言 Web 框架 beego v2 之读操作

作者头像
frank.
发布2020-12-08 14:52:43
1K0
发布2020-12-08 14:52:43
举报

01

介绍

beego ORM 是一个强大的 Go 语言 ORM 框架。她的灵感主要来自

Django ORM 和 SQLAlchemy。

已支持的数据库驱动有MySQL、PostgreSQL 和 Sqlite3。

beego v2.x 和 beego v1.x 在 ORM 上的区别是,beego v2.x 的 ORM 对象被设计为无状态的,它是线程安全的,建议大家在使用时,一个数据库只对应一个 ORM 对象。

本文全篇都是以 MySQL 为例。

关于 beego ORM 的安装和注册,已在「Golang 语言 Web 框架 beego v2 之写操作」中介绍,本文不再赘述。

02

普通查询

beego ORM 提供了两个普通查询的方法,分别是 Read 和 ReadOrCreate。

Read 方法默认把主键作为查询条件,也可以指定字段作为查询条件,如果指定字段作为查询条件,需要在 Read 方法的第二个参数中传入指定字段的名称。

示例代码:

Read 方法,主键查询

代码语言:javascript
复制
func (u *UserController) Read() {
  o := orm.NewOrm()
  user := &models.User{
    Id: 2,
  }
  err := o.Read(user)
  if err != nil {
    log.Fatalln(err.Error())
    return
  }
  fmt.Printf("user:%+v\n", user)
}

Read 方法,指定字段查询

代码语言:javascript
复制
func (u *UserController) Read() {
  o := orm.NewOrm()
  user := &models.User{
    Name: "Lucy",
  }
  err := o.Read(user, "Name")
  if err != nil {
    log.Fatalln(err.Error())
    return
  }
  fmt.Printf("user:%+v\n", user)
}

ReadOrCreate 方法默认必须传入一个参数作为条件字段,同时支持多个参数作为条件字段。根据条件字段从数据库中读取行,如果不存在,就插入一行。

ReadOrCreate 方法返回三个值,分别为一个 bool 类型,代表是否新插入一行;一个 int64 类型,代表查询对象(或新插入)的 Id;和一个 error 类型的错误。

示例代码:

ReadOrCreate 方法

代码语言:javascript
复制
func (u *UserController) Read() {
  o := orm.NewOrm()
  user := &models.User{
    Name: "Alan",
    Age: 37,
  }
  created, id, err := o.ReadOrCreate(user,"Name", "Age")
  if err != nil {
    log.Fatalln(err.Error())
    return
  }
  fmt.Printf("Created:%t,id:%d\n", created, id)
  fmt.Printf("user:%+v\n", user)
}

03

高级查询

beego ORM 高级查询是通过获取一个 QuerySeter 对象,使用 QuerySeter 对象的方法实现高级查询。

QuerySeter 接口包含的方法:

代码语言:javascript
复制
type QuerySeter interface {
    Filter(string, ...interface{}) QuerySeter
    FilterRaw(string, string) QuerySeter
    Exclude(string, ...interface{}) QuerySeter
    SetCond(*Condition) QuerySeter
    GetCond() *Condition
    Limit(limit interface{}, args ...interface{}) QuerySeter
    Offset(offset interface{}) QuerySeter
    GroupBy(exprs ...string) QuerySeter
    OrderBy(exprs ...string) QuerySeter
    ForceIndex(indexes ...string) QuerySeter
    UseIndex(indexes ...string) QuerySeter
    IgnoreIndex(indexes ...string) QuerySeter
    RelatedSel(params ...interface{}) QuerySeter
    Distinct() QuerySeter
    ForUpdate() QuerySeter
    Count() (int64, error)
    Exist() bool
    Update(values Params) (int64, error)
    Delete() (int64, error)
    PrepareInsert() (Inserter, error)
    All(container interface{}, cols ...string) (int64, error)
    One(container interface{}, cols ...string) error
    Values(results *[]Params, exprs ...string) (int64, error)
    ValuesList(results *[]ParamsList, exprs ...string) (int64, error)
    ValuesFlat(result *ParamsList, expr string) (int64, error)
    RowsToMap(result *Params, keyCol string, valueCol string) (int64, error)
    RowsToStruct(ptrStruct interface{}, keyCol string, valueCol string) (int64, error)
}

QuerySeter 对象

在介绍 QuerySeter 对象的方法之前,先给大家介绍如何获取一个 QuerySeter 对象,获取一个 QuerySeter 对象有三种方式,第一种是调用 ormer 的QueryTable 方法,参数传入一个 string 类型的表名;第二种是调用 ormer 的QueryTable 方法,参数传入一个结构体的地址;第三种是调用 ormer 的QueryTable 方法,参数传入一个指针类型的结构体;

示例代码:

代码语言:javascript
复制
var user models.User
err := o.QueryTable("beego_user").One(&user)
err = o.QueryTable(&user).One(&user)
err = o.QueryTable(new(models.User)).One(&user)

本小节我们主要介绍一下 One 方法、All 方法和 Count 方法。

One 方法

One 方法返回单条记录,默认情况下,返回主键升序的第一条记录。如果指定查询条件,则返回符合查询条件的一条记录,如果符合查询条件的记录大于 一条,则返回错误。

One 方法默认返回记录的所有字段,如果需要指定返回的字段,可以在 One 方法中传入需要返回的字段名称,多个字段名称以英文逗号分隔,未指定的返回字段,返回该字段的类型零值。

示例代码:

代码语言:javascript
复制
func (u *UserController) Read() {
  o := orm.NewOrm()
  var user models.User
  // string 类型的表名
  // err := o.QueryTable("beego_user").One(&user)
  // 结构体的地址
  // err := o.QueryTable(&user).One(&user)
  // 使用对象作为表名
  err := o.QueryTable(new(models.User)).One(&user)
  // 指定返回字段,其他字段返回字段类型的零值
  // err := o.QueryTable(new(models.User)).One(&user, "Id", "Name")
  if err != nil {
    log.Fatalln(err.Error())
    return
  }
  fmt.Printf("user:%+v\n", user)
}

All 方法

All 方法返回对应的结果集对象,默认受 Limit 限制,最多显示 1000 条数据。All 方法的参数可以接收 []Type 和 *[]Type 两种形式的切片,如果需要指定查询的字段,可以在第二个参数开始传入字段名称,多个字段名称以英文逗号分隔,未指定查询的字段,返回字段类型的零值。

示例代码:

代码语言:javascript
复制
func (u *UserController) Read() {
  o := orm.NewOrm()
  var users []models.User
  rows, err := o.QueryTable("beego_user").All(&users)
  // 指定返回字段,其他字段返回字段类型的零值
  // rows, err := o.QueryTable("beego_user").All(&users, "Id", "Name")
  if err != nil {
    log.Fatalln(err.Error())
    return
  }
  fmt.Printf("rows:%d users:%+v\n", rows, users)
}

Count 方法

Count 方法返回结果集行数。

示例代码:

代码语言:javascript
复制
func (u *UserController) Read() {
  o := orm.NewOrm()
  num, err := o.QueryTable(new(models.User)).Count()
  if err != nil {
    log.Fatalln(err.Error())
    return
  }
  fmt.Println("num:", num)
}

04

条件查询

上一小节介绍的查询方式,都没有使用查询条件,本小节内容介绍条件查询,在介绍条件查询之前,先来介绍一下 expr,expr 是 QuerySeter 用于描述字段和描述sql 操作符的一种表达方式。

字段组合的前后顺序依照表的关系,比如 User 表拥有 Profile 的外键,那么对 User 表查询对应的 Profile.Age 为条件,则使用 Profile__Age。

注意,字段的分隔符号使用双下划线 __,除了描述字段, expr 的尾部可以增加操作符以执行对应的 sql 操作。比如 Profile__Age__gt 代表 Profile.Age > 18 的条件查询。

expr 示例代码:

代码语言:javascript
复制
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

注释后面将描述对应的 sql 语句,仅仅是描述 expr 的类似结果,并不代表实际生成的语句。

表达式和操作符

在介绍 QuerySeter 的方法之前,先介绍表达式和操作符,表达式和操作符适用于 QuerySeter 的所有方法。

表达式

  • 等于
  • 大于 gt
  • 大于等于 gte
  • 小于 lt
  • 小于等于 lte
  • IN
  • isnull (true:isnull / false:is not null)

操作符

代码语言:javascript
复制
exact 等于(区分字母大小写)iexact 等于(不区分大小写)contains Like(区分大小写)icontains Like( 不区分大小写)startswith (前置模糊查询,区分大小写)istartswith(前置模糊查询,不区分大小写)endswith(后置模糊查询,区分大小写)iendswith(后置模糊查询,不区分大小写)

QuerySeter 的方法

Filter 包含

Filter 方法用来过滤查询结果,起到「包含条件」的作用。

Exclude 排除

Exclude 方法用来过滤查询结果,起到「排除条件」的作用。

代码语言:javascript
复制
Limit 限制条数

Limit 方法限制最大返回的记录数,默认值为 1000。第二个参数可以设置 offset,需要特别注意的是,这里的 limit / offset 和原生 sql 中的 limit / offset 是反过来的。

代码语言:javascript
复制
Offset 偏移

Offset 方法用来设置偏移量。

代码语言:javascript
复制
OrderBy 排序 "column" means ASC, "-column" means DESC.

OrderBy 方法用于排序,参数使用 expr 表达方式,默认是 ASC 排序规则,在 expr 前面用减号「-」表示 DESC 排序规则。

Distinct 方法

Distinct 方法返回指定字段不重复的查询结果。

代码语言:javascript
复制
Exist 是否存在

Exist 方法用于判断符合查询条件的结果是否存在。

示例代码:

代码语言:javascript
复制
func (u *UserController) Read() {
  o := orm.NewOrm()
  // 条件查询
  var users []models.User
  // Filter 包含
  // 表达式和操作符
  // 等于
  err := o.QueryTable(new(models.User)).Filter("id", 2).One(&users)
  // 大于
  // num, err := o.QueryTable(new(models.User)).Filter("id__gt", 9).All(&users)
  // 大于等于
  // num, err := o.QueryTable(new(models.User)).Filter("id__gte", 9).All(&users)
  // 小于
  // num, err := o.QueryTable(new(models.User)).Filter("id__lt", 5).All(&users)
  // 小于等于
  // num, err := o.QueryTable(new(models.User)).Filter("id__lte", 5).All(&users)
  // IN
  // num, err := o.QueryTable(new(models.User)).Filter("id__in", 2, 4).All(&users)
  // isnull (true:isnull / false: is not null)
  // num, err := o.QueryTable(new(models.User)).Filter("id__isnull", false).All(&users)
  // num, err := o.QueryTable(new(models.User)).Filter("id__isnull", true).All(&users)

  // exact 等于(区分字母大小写)
  // num, err := o.QueryTable(new(models.User)).Filter("name__exact", "frank").All(&users)
  // iexact 等于(不区分大小写)
  // num, err := o.QueryTable(new(models.User)).Filter("name__iexact", "frank").All(&users)

  // contains Like(区分大小写)
  // num, err := o.QueryTable(new(models.User)).Filter("name__contains", "frank").All(&users)
  // icontains Like( 不区分大小写)
  // num, err := o.QueryTable(new(models.User)).Filter("name__icontains", "frank").All(&users)

  // startswith (前置模糊查询,区分大小写)
  // num, err := o.QueryTable(new(models.User)).Filter("name__startswith", "fran").All(&users)
  // istartswith(前置模糊查询,不区分大小写)
  // num, err := o.QueryTable(new(models.User)).Filter("name__istartswith", "fran").All(&users)

  // endswith(后置模糊查询,区分大小写)
  // num, err := o.QueryTable(new(models.User)).Filter("name__endswith", "er").All(&users)
  // iendswith(后置模糊查询,不区分大小写)
  // num, err := o.QueryTable(new(models.User)).Filter("name__iendswith", "er").All(&users)

  // Exclude 排除
  // num, err := o.QueryTable(new(models.User)).Exclude("name__exact", "frank").All(&users)

  // Limit 限制条数
  // num, err := o.QueryTable(new(models.User)).Limit(4).All(&users)

  // Offset 偏移
  // num, err := o.QueryTable(new(models.User)).Offset(4).All(&users)

  // OrderBy 排序 "column" means ASC, "-column" means DESC.
  // num, err := o.QueryTable(new(models.User)).OrderBy("id").All(&users)
  // num, err := o.QueryTable(new(models.User)).OrderBy("-id").All(&users)

  // Distinct 去重
  // num, err := o.QueryTable(new(models.User)).Filter("id__gt", 9).Distinct().All(&users, "Age")

  // Exist 是否存在
  // isExisted := o.QueryTable(new(models.User)).Filter("name__exact", "frank1").Exist()
  // fmt.Println("isExisted:", isExisted)

  if err != nil {
    log.Fatalln(err.Error())
    return
  }
  fmt.Printf("user:%+v\n", users)
}

05

原生 SQL 查询

beego ORM 原生 SQL 查询,通过获取一个 RawSeter 对象,使用 RawSeter 对象的 Raw 方法,实现原生 SQL 查询。

Raw 方法,参数 1 是原生 sql 语句的字符串,参数 2 是原生 sql 语句的参数,该参数支持模型结构体,切片和数组。

RawSeter 接口的方法:

代码语言:javascript
复制
type RawSeter interface {
    Exec() (sql.Result, error)
    QueryRow(containers ...interface{}) error
    QueryRows(containers ...interface{}) (int64, error)
    SetArgs(...interface{}) RawSeter
    Values(container *[]Params, cols ...string) (int64, error)
    ValuesList(container *[]ParamsList, cols ...string) (int64, error)
    ValuesFlat(container *ParamsList, cols ...string) (int64, error)
    RowsToMap(result *Params, keyCol string, valueCol string) (int64, error)
    RowsToStruct(ptrStruct interface{}, keyCol string, valueCol string) (int64, error)
    Prepare() (RawPreparer, error)
}

接下来,我们来介绍一下 QueryRow 方法和 QueryRows 方法。

QueryRow 方法

QueryRow 方法返回单条查询数据,不定长参数接收指针类型。

示例代码:

代码语言:javascript
复制
func (u *UserController) Read() {
  o := orm.NewOrm()
    var user models.User
  err := o.Raw("SELECT id,name,age FROM beego_user WHERE id = ?", 2).QueryRow(&user)
  if err != nil {
    log.Fatalln(err.Error())
    return
  }
  fmt.Printf("user:%+v\n", user)
}

QueryRows 方法

QueryRows 方法返回多条查询数据,不定长参数接收指针类型。返回结果是查询结果集的数量和错误。

示例代码:

代码语言:javascript
复制
func (u *UserController) Read() {
  o := orm.NewOrm()
  var users []models.User
  ids := []int{1,3,5}
  num, err := o.Raw("SELECT id,name,age FROM beego_user WHERE id IN (?,?,?)", ids).QueryRows(&users)
  if err != nil {
    log.Fatalln(err.Error())
    return
  }
  fmt.Printf("nums:%d user:%+v\n", num, users)
}

06

总结

本文主要介绍 beego ORM 的读操作,包含普通查询、高级查询和原生 SQL 查询,先是介绍了普通查询,然后是介绍高级查询,包含 expr 表达式,QuerySeter 接口和其部分方法的使用,最后介绍了 RawSeter 接口和其部分方法的使用。限于篇幅,没有介绍关联查询和构造查询,关于未提及的内容,读者朋友可以参考官方手册。

参考资料:

https://beego.me/docs

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-12-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Go语言开发栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 SQL Server
腾讯云数据库 SQL Server (TencentDB for SQL Server)是业界最常用的商用数据库之一,对基于 Windows 架构的应用程序具有完美的支持。TencentDB for SQL Server 拥有微软正版授权,可持续为用户提供最新的功能,避免未授权使用软件的风险。具有即开即用、稳定可靠、安全运行、弹性扩缩等特点。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档