Beego脱坑(十四)ORM高级查询

19 篇文章 36 订阅

title: Beego脱坑(十四)ORM高级查询
tags: go,beego,orm
author : Clown95


本文将讲述beego ORM的一些高级查询,这也是ORM最核心的部分,本文所有的操作都基于下面的student

Operators

在beego ORM中也有类似于SQL语句中的操作符,欲善其事,必利其器,我们先来了解他们,beego ORM目前支持的操作符为:

操作符说明等同Sql操作符
gtgreater的缩写,表示大于的意思>
gtegreater than or equal的缩写,即大于等于>=
ltless than的缩写,表示小于<
lteless thanor equal的缩写,小于等于<=
in等同与sql语言中的inin
exact等于=
contains包含,一般用于字符类型,如包含某某字符like '%查询内容%'
startswith以…起始,一般用于字符类型,如从什么字符开始like '开始字符%'
endswith以…结束 ,一般用于字符类型,如以什么字符结束like '%结束字符'
isnull表示改字段不能为空

在beego中 操作符前面添加 字母 i 表示忽略大小写,如 iexact、icontains 、istartswith 和iendswith 

exact

我们最先演示下exact 它相当于 = ,现在我们需要通过它查询出 stu_id =3 的一条数据。

func (this *OperatorsController) GetExact() {
    orm := orm.NewOrm()
    // 获取表句柄
    stu := Student{}
    qs := orm.QueryTable("student")
    // select * from student where id =3;
    err := qs.Filter("stu_id__exact", 3).One(&stu) // 过滤器
    if err != nil {
        this.Ctx.WriteString(strconv.Itoa(stu.StuId) + " " + stu.Name + " " + stu.Age + " " + stu.Hobby)
    }else{
        this.Ctx.WriteString("查询失败")    
    }
}

上面的代码相当于sql语句 :

select * from student where id =3;
  • QueryTable("student") : 返回 student表的QuerySeter 对象。ORM 以 QuerySeter 来组织查询,每个返回 QuerySeter 的方法都会获得一个新的 QuerySeter 对象;
  • Filter("stu_id__exact" ,3) : 用来过滤查询结果,起到包含条件的作用,第一个参数是我匹配规则,第二个参数是我们匹配的值 ; 使用如果使用操作符,字段和操作符直接使用两个"_"连接,具体格式为:字段__操作符;
  • One(&stu) : 返回单条记录 ,参数一般是结构体对象。

gte

现在我们来使用 gte 获取 age>=25岁的所有数据, 下面我们看代码。

func (this *OperatorsController) GetAllGte() {
    orm := orm.NewOrm()
    var stus = []*Student{}
    // 获取表句柄
    qs := orm.QueryTable("student")
    // select * from student where age>=25;
    n, err := qs.Filter("age__gte", 20).All(&stus) // 过滤器
    if err == nil && n > 0 {
        for i := 0; i < len(stus); i++ {
            this.Ctx.WriteString(strconv.Itoa(stus[i].StuId) + " " + stus[i].Name + " " + stus[i].Age + " " + stus[i].Hobby + "\n")
        }
    } else {
        this.Ctx.WriteString("查询失败")
    }
}

上面的代码相当于sql语句:

select * from student where age>=25;
  • All(&stus) : 返回对应的结果集对象。 和One不一样的是,All返回所有符合条件的数据,参数是指针切片( []Type 或者[]*Type ),返回数据cols和error

in

现在我们通过 in 查询 stu_id 为 1、4、5、10的数据集。

func (this *OperatorsController) GetIn() {
    orm := orm.NewOrm()
    var stus = []*Student{}
    // 获取表句柄
    qs := orm.QueryTable("student")
    // select * from student where stu_id in(1,4,5,10);
    n, err := qs.Filter("stu_id__in",1,4,5,10 ).All(&stus) // 过滤器
    if err == nil && n > 0 {
        for i := 0; i < len(stus); i++ {
            this.Ctx.WriteString(strconv.Itoa(stus[i].StuId) + " " + stus[i].Name + " " + stus[i].Age + " " + stus[i].Hobby + "\n")
        }
    } else {
        this.Ctx.WriteString("查询失败")
    }
}

上面的代码相当于sql语句:

select * from student where stu_id in(1,4,5,10);

contains

接着我们使用 contains 来查询 name中包含 "小" 字的数据集。

func (this *OperatorsController) GetContains() {
    orm := orm.NewOrm()
    var stus = []*Student{}
    // 获取表句柄
    qs := orm.QueryTable("student")
    // select * from student where name like '小%';
    n, err := qs.Filter("name__contains", "小").All(&stus) // 过滤器
    if err == nil && n > 0 {
        for i := 0; i < len(stus); i++ {
            this.Ctx.WriteString(strconv.Itoa(stus[i].StuId) + " " + stus[i].Name + " " + stus[i].Age + " " + stus[i].Hobby + "\n")
        }
    } else {
        this.Ctx.WriteString("查询失败")
    }
}

上面的代码相当于sql语句:

select * from student where name like '小%';

操作符我们就演示到这里,其他的几个用法都大同小异,大家可以自己拓展。

 

高级查询接口

高级查询接口我们在 Operators 部分里面,使用过 Filter、One、All这三个了。我们就不在重复介绍了,我们主要来了解下其他的接口函数。

方法说明
Exclude用来过滤查询结果,起到 排除条件的作用,相当于!Filter
Limit限制最大返回数据行数
Offset设置偏移行数
GroupBy数据分组
OrderBy数据排序
Distinct获取不重复的数据
Count依据当前的查询条件,返回结果行数
Exist判断查询的数据是否存在
Values返回结果集数据,存储到map中
ValuesList顾名思义,返回的结果集以slice存储
PrepareInsert用于批量插入数据
Delete依据当前查询条件,进行批量删除操作
Update依据当前查询条件,进行批量更新操作

Exclude

现在我们来使用Exclude 排除 年龄小于等于25的数据.

func (this * ADvancedApiController) GetExclude(){
    orm := orm.NewOrm()
    var stus = []*Student{}
    // 获取表句柄
    qs := orm.QueryTable("student")
    //select * from student where not age <=25 ;
    n, err := qs.Exclude("age__lte",25).All(&stus)
    if err == nil && n > 0 {
        for i := 0; i < len(stus); i++ {
            this.Ctx.WriteString(strconv.Itoa(stus[i].StuId) + " " + stus[i].Name + " " + stus[i].Age + " " + stus[i].Hobby + "\n")
        }
    } else {
        this.Ctx.WriteString("查询失败")
    }
}

上面的代码相当于sql语句:

select * from student where not age <=25 ;

Limit

有时候数据过多,我们只想显示部分数据,比如现在我们只需要显示前5个数据

func (this * ADvancedApiController) GetLimit(){
    orm := orm.NewOrm()
    var stus = []*Student{}
    // 获取表句柄
    qs := orm.QueryTable("student")
    //select * from student limit 5 ;
    n, err := qs.Limit(5) .All(&stus)
    if err == nil && n > 0 {
        for i := 0; i < len(stus); i++ {
            this.Ctx.WriteString(strconv.Itoa(stus[i].StuId) + " " + stus[i].Name + " " + stus[i].Age + " " + stus[i].Hobby + "\n")
        }
    } else {
        this.Ctx.WriteString("查询失败")
    }
}

上面的代码相当于sql语句:

select * from student limit 5 ;

当然我们还可以设置偏移量来设置分页 ,我们来修改Limit,显示6-10的数据:

n, err := qs.Limit(5,5) .All(&stus)

GroupBy

通过 age 进行分组

func (this * ADvancedApiController) GetGroupBy(){
    orm := orm.NewOrm()
    var stus = []*Student{}
    qs := orm.QueryTable("student")
    n, err := qs.GroupBy("age").All(&stus)
    if err == nil && n > 0 {
        for i := 0; i < len(stus); i++ {
            this.Ctx.WriteString(strconv.Itoa(stus[i].StuId) + " " + stus[i].Name + " " + stus[i].Age + " " + stus[i].Hobby + "\n")
        }
    } else {
        this.Ctx.WriteString("查询失败")
    }
}

OrderBy

通过 age 和 stu_id 进行排序 表达式前面使用 "-" 代表降序排序

func (this * ADvancedApiController) GetOrderBy(){
    orm := orm.NewOrm()
    var stus = []*Student{}
    qs := orm.QueryTable("student")
    n, err := qs.OrderBy("-age","stu_id").All(&stus)
    if err == nil && n > 0 {
        for i := 0; i < len(stus); i++ {
            this.Ctx.WriteString(strconv.Itoa(stus[i].StuId) + " " + stus[i].Name + " " + stus[i].Age + " " + stus[i].Hobby + "\n")
        }
    } else {
        this.Ctx.WriteString("查询失败")
    }
}

Count

使用Count 查询有多少行数据

func (this *ADvancedApiController) GetCount() {
    orm := orm.NewOrm()
    //select count(*) from student;
    n, err := orm.QueryTable("student").Count()
    if err != nil {
        this.Ctx.WriteString("查询出错!\n")
        return
    }else {
        this.Ctx.WriteString("n = " + strconv.Itoa(int(n)))
    }
}

上面的代码相当于sql语句:

select count(*) from student;

Exist

我们用 Exist 判断 stu_id =8 和 stu_id =15 的数据是否存在

func (this *ADvancedApiController) GetExist() {
    orm := orm.NewOrm()
    qs := orm.QueryTable("student")
    flag := qs.Filter("stu_id", 8).Exist()
    if flag {
        this.Ctx.WriteString("stu_id=8 存在\n")
    }else {
        this.Ctx.WriteString("stu_id=8 不存在\n")
    }
    flag = qs.Filter("stu_id", 15).Exist()
    if flag {
        this.Ctx.WriteString("stu_id=15 存在\n")
    }else {
        this.Ctx.WriteString("stu_id=15 不存在\n")
    }
}

Values

我们还可以 使用Values 返回结果集的 key => value 值 ,key 为Model里的Field name, value的值是interface{}类型,如果你要将value赋值给struct中的某字段,需要根据结构体对应字段类型使用断言获取真实值。

func (this *ADvancedApiController) GetValues() {
    //将每一条记录的字段作为键,数据作为值存入map中,每个map就是一条记录。
    var maps []orm.Params //[map, map, map]
    orm := orm.NewOrm()
    _, err := orm.QueryTable("student").Values(&maps, )
    if err != nil {
        this.Ctx.WriteString("查询出错!")
        return
    }
    for _, m := range maps {
        this.Ctx.WriteString(m["Name"].(string) + " " + m["Age"].(string) + "   " + m["Hobby"].(string) + "\n")
    }
}

当然我们还可以直接指定 expr 级联返回需要的数据

func (this *ADvancedApiController) GetValuesField() {
    //将每一条记录的字段作为键,数据作为值存入map中,每个map就是一条记录。
    var maps []orm.Params //[map, map, map]
    orm := orm.NewOrm()
    _, err := orm.QueryTable("student").Values(&maps, "Name","Hobby")
    if err != nil {
        this.Ctx.WriteString("查询出错!")
        return
    }
    for _, m := range maps {
        this.Ctx.WriteString(m["Name"].(string) + " " + m["Hobby"].(string) + "\n")
    }
}

ValuesList

顾名思义,返回的结果集以slice存储,结果的排列与 Model 中定义的 Field 顺序一致,返回的每个元素值以 string 保存。

func (this *ADvancedApiController) GetValuesList() {
    var list []orm.ParamsList
    orm := orm.NewOrm()
    _, err := orm.QueryTable("student").ValuesList(&list, "Name", "Age", "Hobby")
    if err != nil {
        this.Ctx.WriteString("查询出错!")
        return
    }
    for _, row := range list {
        for _, col := range row {
            this.Ctx.WriteString(col.(string) + " ")
        }
        this.Ctx.WriteString("\n")
    }
}

 

PrepareInsert

我们使用PrepareInsert 在添加点数据,并且我们多提交一次数据,方便演示下面的批量删除

func (this *ADvancedApiController) GetPrepareInsert() {

    var stus []*Student
    stu1 := Student{Name:"银之介", Age:"60", Hobby:"辣妹"}
    stu2 := Student{Name:"正男", Age:"5", Hobby:"小爱"}
    stu3 := Student{Name:"阿呆", Age:"6", Hobby:"甩鼻涕"}
    stu4 := Student{Name:"园长", Age:"56", Hobby:"园艺"}
    stus = append(stus, &stu1, &stu2, &stu3, &stu4)
    orm := orm.NewOrm()
// insert into student(name, age.hobby) values("银之介", "60", "辣妹"), (正男", "5", "小爱");
    insert, _ := orm.QueryTable("student").PrepareInsert()
    for _, stu := range stus {
        _, err := insert.Insert(stu)
        if err != nil {
            fmt.Println("插入错误!\n")
            continue
        }
    }
    insert.Close()
    this.Ctx.WriteString("插入结束!\n")
}

上面的代码相当于sql语句:

insert into student(name, age.hobby) values("银之介", "60", "辣妹"), ....,(园长", "56", "园艺");

Delete

还记得我们刚刚多提交了一次数据插入吗?我们原来的数据stu_id 最大为11, 所以我们删除 stu_id >11 的数据

func (this *ADvancedApiController) GetDelete() {
    orm := orm.NewOrm()
    qs:= orm.QueryTable("student")
    n,err:=qs.Filter("stu_id__gt",11).Delete()
    if err == nil&& n>0 {
        this.Ctx.WriteString("删除成功!\n")

    } else {
        this.Ctx.WriteString("删除失败!\n")
    }
}

Update

现在我们来批量更新下数据,下面我们需要把 stu_id=5 的 Hobby 改为 学习。

func (this *ADvancedApiController) GetUpdate() {
    orm1 := orm.NewOrm()
    qs:= orm1.QueryTable("student")
    n,err:=qs.Filter("stu_id",5).Update(orm.Params{
            "hobby": "学习",
        })
    if err == nil&& n>0 {
        this.Ctx.WriteString("修改成功!\n")

    } else {
        this.Ctx.WriteString("修改失败!\n")
    }
}

看到这里大家应该基本掌握接口的用法了,还有其他部分没演示的,请自行拓展我实在不想写了。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值