智能选择字段

GORM 允许通过 Select 方法选择特定的字段,如果您在应用程序中经常使用此功能,你也可以定义一个较小的结构体,以实现调用 API 时自动选择特定的字段,例如:

  1. type User struct {
    ID int `gorm:"primaryKey;autoIncrement"`
    Name sql.NullString `gorm:"default:'隔壁老王'"`
    Age uint8 `gorm:"default:55"`
    UUID uuid.UUID
    CreatedAt time.Time `gorm:"autoCreateTime"`
    }
    type APIUser struct {
    ID int
    Name string
    }
  1. // 查询时会自动选择ID、Name字段
    db.Debug().Model(new(User)).Find(&apiUsers)
  2. // SELECT `users`.`id`,`users`.`name` FROM `users`

 注意 QueryFields 模式会根据当前 model 的所有字段名称进行 select。

  1. db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{
  2. QueryFields: true,
  3. })
  1. db.Debug().Find(&users)
    // SELECT `users`.`id`,`users`.`name`,`users`.`age`,`users`.`uuid`,`users`.`created_at` FROM `users`

    // Session Mode
  1. db.Debug().Session(&gorm.Session{QueryFields: true}).Find(&users)
    // SELECT `users`.`id`,`users`.`name`,`users`.`age`,`users`.`uuid`,`users`.`created_at` FROM `users`

  

Locking (FOR UPDATE)

GORM 支持多种类型的锁,例如:

  1. // 独占锁
    db.Debug().Clauses(clause.Locking{Strength: "UPDATE"}).Find(&users)
    // SELECT * FROM `users` FOR UPDATE

  1. // 共享锁
  1. db.Debug().Clauses(clause.Locking{
    Strength: "SHARE",
    Table: clause.Table{Name: clause.CurrentTable},
    }).Find(&users)
    // SELECT * FROM `users` FOR SHARE OF `users`

  

子查询

  子查询可以嵌套在查询中,GORM 允许在使用 *gorm.DB 对象作为参数时生成子查询

  1. db.Debug().Where("age > (?)", db.Table("users").Select("avg(age)")).Find(&users)
  2. // SELECT * FROM `users` WHERE age > (SELECT avg(age) FROM `users`)

  1. // 智能选择字段
    type APIUser struct {
    Name string
    Age uint8
    }
    // 子查询
    var users []APIUser
    subQuery := db.Debug().Table("users").Select("avg(age) as age").Where("name IN (?)", []string{"李四", "赵六"})
    db.Debug().Model(&User{}).Where("age > (?)", subQuery).Scan(&users)
    // SELECT * FROM `users` WHERE age > (SELECT avg(age) as age FROM `users` WHERE name IN ('李四','赵六'))

  

From 子查询

  GORM 允许您在 Table 方法中通过 FROM 子句使用子查询,例如:

  1. db.Debug().Table("(?) as u", db.Model(new(User)).Select("name, age")).Where("age > ?", 18).Scan(&users)
  2. // SELECT * FROM (SELECT name, age FROM `users`) as u WHERE age > 18

  1. subQuery1 := db.Model(new(User)).Select("name")
    subQuery2 := db.Model(&Email{}).Select("email")
    db.Debug().Table("(?) as a, (?) as b", subQuery1, subQuery2).Scan(&users)
    // SELECT * FROM (SELECT `name` FROM `users`) as a, (SELECT `email` FROM `emails`) as b // 生成笛卡尔积表

  

Group 条件

  使用 Group 条件可以更轻松的编写复杂 SQL

  1. db.Debug().Model(new(User)).Where(
  2.   db.Where("name <> ?", "老王").Where(db.Where("age = ?", 10).Or("age = ?", 11)),
  3. ).Or(
  4.   db.Where("name <> ?", "李四").Where("age = ?", 55),
  5. ).Scan(&users)
  6. // SELECT * FROM `users` WHERE (name <> '老王' AND (age = 10 OR age = 11)) OR (name <> '李四' AND age = 55)

  

命名参数

  GORM 支持 sql.Named 和 map[string]interface{}{} 形式的命名参数,例如:

  1. db.Debug().Model(&User{}).Where(
  2.   "name = @name OR age = @age", sql.Named("name", "李四"), sql.Named("age", 11),
  3. ).Scan(&apiUsers)
  4. // SELECT * FROM `users` WHERE name = '李四' OR age = 11

  1. db.Debug().Model(new(User)).Where(
    "name=@n", map[string]interface{}{"n": "老王"},
    ).Find(&apiUsers)
    // SELECT `users`.`name`,`users`.`age` FROM `users` WHERE name='老王'

  

Find 至 map

  GORM 允许扫描结果至 map[string]interface{} 或 []map[string]interface{},此时别忘了指定 Model 或 Table,例如:

  1. var m1 map[string]interface{}
  2. db.Debug().Model(new(User)).First(&m1, "id = ?", 5)
  3. // SELECT * FROM `users` WHERE id = 5 ORDER BY `users`.`id` LIMIT 1

  1. var m1 []map[string]interface{}
    db.Debug().Model(new(User)).Find(&m1)
    // SELECT * FROM `users`

  

FirstOrInit

  获取第一条匹配的记录,或者根据给定的条件初始化一个实例(仅支持 sturct 和 map 条件)

  1. // 未找到user,根据给定的条件初始化 struct
    db.Debug().FirstOrInit(&user, &User{Name: sql.NullString{"老王2", true}})
    // SELECT * FROM `users` WHERE `users`.`name` = '老王2' ORDER BY `users`.`id` LIMIT 1
  1. // 找到了user
    db.Debug().Where(&User{Age: 10}).FirstOrInit(&user)
    // SELECT * FROM `users` WHERE `users`.`age` = 10 ORDER BY `users`.`id` LIMIT 1

    // 使用map
  1. db.Debug().FirstOrInit(&user, map[string]interface{}{"name": "李四"})
    // SELECT * FROM `users` WHERE `name` = '李四2' ORDER BY `users`.`id` LIMIT 1

  如果没有找到记录,可以使用包含更多的属性的结构体初始化 user,Attrs 不会被用于生成查询 SQL

  1. // 未找到user,则根据给定的条件和Attrs初始化user
  1. db.Debug().Where(&User{Name: sql.NullString{"赵武", true}}).Attrs(&User{Age: 99}).FirstOrInit(&user)
    // SELECT * FROM `users` WHERE `users`.`name` = '赵武' ORDER BY `users`.`id` LIMIT 1

  1. // 找到了name=李四的user,则忽略:Attrs
    db.Debug().Where("name = ?", "李四").Attrs(User{Age: 88}).FirstOrInit(&user)
    // SELECT * FROM `users` WHERE name = '李四' ORDER BY `users`.`id` LIMIT 1

  不管是否找到记录,Assign 都会将属性赋值给 struct,但这些属性不会被用于生成查询 SQL,也不会被保存到数据库

  1. // 未找到user,根据条件和Assign初始化struct
    db.Debug().Where(User{Name: sql.NullString{"NonUser", true}}).Assign(User{Age: 5}).FirstOrInit(&user)
    // SELECT * FROM `users` WHERE `users`.`name` = 'NonUser' ORDER BY `users`.`id` LIMIT 1
  1. // 找到name=李四的user, 依然会更新Assign属性
    db.Debug().Where(User{Name: sql.NullString{"老王", true}}).Assign(User{Age: 5}).FirstOrInit(&user)
    // SELECT * FROM `users` WHERE `users`.`name` = '老王' ORDER BY `users`.`id` LIMIT 1

  

FirstOrCreate

  获取第一条匹配的记录,或者根据给定的条件创建一条新纪录(仅支持 sturct 和 map 条件)

  1. // 未找到user,则根据给定的条件创建一条新纪录
    db.Debug().Attrs(User{Name: sql.NullString{"马艳娜", true}}).FirstOrCreate(&user, User{Age: 12})
    // SELECT * FROM `users` WHERE `users`.`age` = 12 ORDER BY `users`.`id` LIMIT 1
    // INSERT INTO `users` (`name`,`age`,`uuid`,`created_at`) VALUES ('马艳娜',12,'00000000-0000-0000-0000-000000000000','2021-11-19 10:04:54.991')

  1. // 找到了Age = 12的user,同时也把Assign属性赋值给age,更新数据库的Assign属性
    db.Debug().Where(User{Age: 12}).Assign(map[string]interface{}{
    "name": "马亚南",
    }).FirstOrCreate(&user)
    // SELECT * FROM `users` WHERE `users`.`age` = 12 ORDER BY `users`.`id` LIMIT 1
    // UPDATE `users` SET `name`='马亚南' WHERE `users`.`age` = 12 AND `id` = 6 ORDER BY `users`.`id` LIMIT 1

  如果没有找到记录,可以使用包含更多的属性的结构体创建记录,Attrs 不会被用于生成查询 SQL 。

  不管是否找到记录,Assign 都会将属性赋值给 struct,并将结果写回数据库

  未找到 user,根据条件和 Attrs 属性创建记录, 找到了 `name` = `jinzhu` 的 user,则忽略 Attrs

  未找到 user,根据条件和 Assign 属性创建记录,  找到了 `name` = `jinzhu` 的 user,依然会根据 Assign 更新记录

迭代

  GORM 支持通过行进行迭代

  1. // ScanRows方法用于将一行Rows扫描至结构体
    rows, _ := db.Model(&User{}).Rows()
    for rows.Next() {
    var user User
    db.ScanRows(rows, &user)
    myPrint(user)
    }

  

FindInBatches

  用于批量查询并处理记录

  1. var users []User
    db.Debug().FindInBatches(&users, 3, func(tx *gorm.DB, batch int) error {
    for _, result := range users {
    spew.Println(result)
    }
    spew.Println(tx.RowsAffected) // 本次批量操作影响的记录数
    return nil
    })
    /*
    SELECT * FROM `users` ORDER BY `users`.`id` LIMIT 3
    5是根据上次查询的最后一个ID确定的
    SELECT * FROM `users` WHERE `users`.`id` > 5 ORDER BY `users`.`id` LIMIT 3
    */

  

查询钩子

  对于查询操作,GORM 支持 AfterFind 钩子,查询记录后会调用它

  1. func (u *User) AfterFind(tx *gorm.DB) (err error) {
    // 查询之后会调用的钩子
    if u.Age > 20 {
    spew.Println("您的岁数是%d,超过20岁了", u.Age)
    }
    return
    }

  

Pluck

  Pluck 用于从数据库查询单个列,并将结果扫描到切片。如果您想要查询多列,您应该使用 Select 和 Scan

  1. var ages []int
    db.Debug().Table("users").Pluck("age", &ages)
    // SELECT `age` FROM `users`

  1. var names []string
    db.Debug().Model(&User{}).Distinct().Pluck("name", &names)
    // SELECT DISTINCT `name` FROM `users`

  1. // Distinct Select
    var users []APIUser
    db.Debug().Model(&User{}).Distinct().Select("name, age").Scan(&users)
    // SELECT distinct name, age FROM `users`

  1. // 超过一列的查询,应该使用 `Scan` 或者 `Find`,例如:
    db.Select("name", "age").Scan(&users)
    db.Select("name", "age").Find(&users)

  

Scopes

  Scopes允许你指定常用的查询,可以在调用方法时引用这些查询

  1. func LaoWang(db *gorm.DB) *gorm.DB {
    return db.Where("name = ?", "老王")
    }
    func Age10(db *gorm.DB) *gorm.DB {
    return db.Where(map[string]interface{}{"age": 10})
    }
  1. // Scopes允许你指定常用的查询,可以在调用方法时引用这些查询
    var users []User
    db.Debug().Scopes(LaoWang, Age10).Find(&users) // 查询name=老王而且age=10的users
    // SELECT * FROM `users` WHERE name = '老王' AND `age` = 10

  1. func Age10Or11(age []int) func(db *gorm.DB) *gorm.DB {
    return func(db *gorm.DB) *gorm.DB {
    return db.Where("age IN (?)", age)
    }
    }
  1. db.Debug().Scopes(Age10Or11([]int{10, 11})).Find(&users) // 查询age = 10或age=11的users
    // SELECT * FROM `users` WHERE age IN (10,11)

  

Count

  Count 用于获取匹配的记录数

  1. var count int64
    db.Debug().Model(new(User)).Count(&count)
    // SELECT count(*) FROM `users`

  1. var count int64
    db.Debug().Table("users").Distinct("name").Count(&count)
    // SELECT COUNT(DISTINCT(`name`)) FROM `users`

  1. var count int64
    db.Debug().Model(&User{}).Select("count(distinct(name))").Count(&count)
    // SELECT count(distinct(name)) FROM `users`

  

gorm中的高级查询的更多相关文章

  1. mybatis中的高级查询

    Mybatis作为一个ORM框架,肯定是支持sql高级查询的. 下面的一个案例来为大家详细讲解mybatis中的高级查询. 案例说明: 此案例的业务关系是用户,订单,订单详情与商品之间的关系. 以订单 ...

  2. 03-oracle中的高级查询

    1.连接查询 1.1 使用连接谓词指定的连接 介绍: 在连接谓词表示形式中,连接条件由比较运算符在WHERE子句中给出,将这种表示形式称为连接谓词表示形式,连接谓词又称为连接条件. 语法: [< ...

  3. gorm中的基本查询

    检索单个对象 GORM 提供了 First.Take.Last 方法,以便从数据库中检索单个对象.当查询数据库时它添加了 LIMIT 1 条件 // 获取第一条记录(主键升序) db.First(&a ...

  4. mysql中的高级查询

    以前学习的查询语法: select 字段名 from 表名 where 条件 其实,查询的语法变化很多: 1. select 可以查询表达式, 表达式就是 运算符+操作数. 比如 1 + 1 2 * ...

  5. MongoDB中的高级查询(二)

    $mod取模运算 查询index对5取模运算等于1的数据. $not $not是元条件句,即可以用在任何其他条件之上.查询index对5取模运算不等于1的数据. $exists判断字段是否存在 查询出 ...

  6. mysql中的高级查询语句

    此随笔用到的数据全是来自  关于mysql中表关系的一些理解(一对一,一对多,多对多) 提及的    学院表,学生表,学生详情表,选课表,课程表 单标查询:(查看学生表的学生名单) select st ...

  7. MongoDB高级查询详细

    前言 前几篇,老玩家绕道即可,新手晚上闲着也是蛋疼,不如把命令敲一边,这样你就会对MongoDB有一定的掌握啦.如果没有安装MongoDB去看我的上一篇博客  MongoDB下载安装与简单增删改查 前 ...

  8. mongodb高级查询

    前几篇,老玩家绕道即可,新手晚上闲着也是蛋疼,不如把命令敲一边,这样你就会对MongoDB有一定的掌握啦.如果没有安装MongoDB去看我的上一篇博客  MongoDB下载安装与简单增删改查 前奏:启 ...

  9. 循序渐进VUE+Element 前端应用开发(29)--- 高级查询条件的界面设计

    在系统模块中的业务列表展示里面,一般我们都会在列表中放置一些查询条件,如果是表字段不多,大多数情况下,放置的条件有十个八个就可以了,如果是字段很多,而这些条件信息也很关键的时候,就可能放置很多条件,但 ...

随机推荐

  1. JAVA获取当前日期指定天数之后的日期

    /** * 获取day天之后的日期 * @param day 天数 * @return */ public static String getDate(int day){ Calendar calen ...

  2. mac OSX使用spdlog1.7

    !!版权声明:本文为博主原创文章,版权归原文作者和博客园共有,谢绝任何形式的 转载!! 作者:mohist 注意️ 请选择对c++11支持较为完善的编译器,因为spdlog一直更新.   本机演示环境 ...

  3. vc++ 调用winapi调节屏幕亮度

    !!版权声明:本文为博主原创文章,版权归原文作者和博客园共有,谢绝任何形式的 转载!! 作者:mohist ---- 已经更正文章中错误的地方, 时间: 10/10/2020--------- 自己封 ...

  4. 【LeetCode】989. Add to Array-Form of Integer 解题报告(C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 数组转整数再转数组 模拟加法 日期 题目地址:htt ...

  5. 【LeetCode】188. Best Time to Buy and Sell Stock IV 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...

  6. ELK集中化日志解决方案——看这一篇全搞定

    一.前言 在软件发开技术管理里有两个永恒经典的问题,适合我们初到一家软件企业或一家公司的科技团队,来判断自己该从哪里入手帮助整个团队提升科技水平和产能.问题一是"在我们团队里,只涉及一行代码 ...

  7. 3 - 基于ELK的ElasticSearch 7.8.x技术整理 - 高级篇( 偏理论 )

    4.ES高级篇 4.1.集群部署 集群的意思:就是将多个节点归为一体罢了( 这个整体就有一个指定的名字了 ) 4.1.1.window中部署集群 - 了解即可 把下载好的window版的ES中的dat ...

  8. 编写Java程序,使用List集合和Map集合输出 市和区

    如图: 代码: import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java ...

  9. 【操作系统】I/O多路复用 select poll epoll

    @ 目录 I/O模式 I/O多路复用 select poll epoll 事件触发模式 I/O模式 阻塞I/O 非阻塞I/O I/O多路复用 信号驱动I/O 异步I/O I/O多路复用 I/O 多路复 ...

  10. Swoole 中使用 PDO 连接池、Redis 连接池、Mysqli 连接池

    连接池使用说明 所有连接池的实现均基于 ConnectionPool 原始连接池: 连接池的底层原理是基于 Channel 的自动调度: 开发者需要自己保证归还的连接是可重用的: 若连接不可重用,需要 ...