Gorm

Gorm Model Find First Where等查询函数的区别

月盾

gorm是一款优秀的国产golang orm关系型数据库框架,在国内外使用比较广泛。它的链式调用还算是一种符合人类思维的风格。

不过在使用过程中也遇到一些困扰,比如:Model, Find, First, Where这些函数该什么时候使用,有时候会有边界不清楚,使用混乱的情况。

以下代码示例使用v2版本,v1和v2大体上相同,有些细微的不同

Where和Find

search := User{UserName:"月盾"}
db.Find(&user, search)
// SELECT * FROM `user` WHERE `user`.`user_name` = '月盾'

db.Where(search).Find(&user)
// SELECT * FROM `user` WHERE `user`.`user_name` = '月盾'

以上两种查询方式结果一样。

Find(dest interface{}, conds ...interface{})Find函数有两个参数,dest是数据接收者,conds是查询条件。所以Find也是可以代替Where来传入条件的。

Where的参数主要分为两类:String,Struct&Map。还有其他不常用类型。

String参数

当使用string参数时,使用方式类似于fmt.Printf,第一个参数为字符串格式,使用?作为占位符,后面的参数作为值。

Struct&Map参数

使用结构体和映射作为参数时,则推荐一个参数即可,struct和map本身就是键值对格式。否则容易引起混淆。比如这样的:

db.Where(&User{Name: "jinzhu"}, "name", "Age").Find(&users)
// SELECT * FROM users WHERE name = "jinzhu" AND age = 0;

db.Where(&User{Name: "jinzhu"}, "Age").Find(&users)
// SELECT * FROM users WHERE age = 0;

注意 当使用结构作为条件查询时,GORM 只会查询非零值字段。这意味着如果您的字段值为 0、’’、false 或其他 零值,该字段不会被用于构建查询条件,例如:

go单元测试初始化

月盾

go单元测试会遇到这样的场景: 写好了service层函数getUser()。然后测试测试getUser函数。有个问题是,函数中使用了数据库连接,如果直接测试的话会报错误,比如空指针错误。

panic: runtime error: invalid memory address or nil pointer dereference [recovered] panic: runtime error: invalid memory address or nil pointer dereference [signal 0xc0000005 code=0x0 addr=0xb0 pc=0x167680d]

如果遇到这种情况很有可能就是数据库连接未初始化。但是单元测试并不会主动去初始化数据库连接。不用担心,有办法。 go test提供了用于初始化的方法:TestMain函数。只需要在这个函数中进行数据库初始化,后面需要用的的数据库连接可直接使用,不需要重复初始化。

func TestMain(m *testing.M) {
	fmt.Println("begin")
	dba, err := gorm.Open("sqlite3", "../../website.db")
	db.SQLLite = dba
	if err != nil {
		panic(err)
	}
	m.Run()
	fmt.Println("end")
}

func TestProjectUsers(t *testing.T) {
	userService := user.NewService(db.SQLLite)
	users, err := userService.GetProjectUsers(25)
	if err != nil {
		t.Error(err)
	}
	t.Log("返回结果:", users)
}

gorm模糊查询和分页查询同时查总条数

月盾

gorm概述

  • 全功能ORM(几乎)
  • 关联(包含一个,包含多个,属于,多对多,多种包含)
  • Callbacks(创建/保存/更新/删除/查找之前/之后)
  • 预加载(急加载)
  • 事务
  • 复合主键
  • SQL Builder
  • 自动迁移
  • 日志
  • 可扩展,编写基于GORM回调的插件
  • 每个功能都有测试
  • 开发人员友好

like查询

gorm提供了丰富的查询功能,在开发中我们经常需要组合查询,比如列表查询,列表查询一般需要支持条件查询,模糊查询,分页查询,数据条数查询。 已上支持基本满足了日常开发需要,一些基本的查询需求可以查看文档得到解决,不过文档并没有覆盖所有日常开发案例,尤其是一些组合需求,本文挑了一段常见的场景。

func (u *userService) GetuserList(offset, limit int, search User) (users []User, count int, err error) {
	query := u.mysql.Model(&User{})
	if search.Name != "" {
		query.Where("name LIKE ?", search.Name+"%")
	}
	if search.Age != "" {
		query.Where("age = ?", search.Age)
	}

	err = query.Offset(offset).Limit(limit).Find(&users).Offset(-1).Limit(-1).Count(&count).Error
	return users, count, err
}

这简单的一小段已经包含了gorm的模糊查询动态条件分页查询数据条数。 这就是一个最常见的列表查询,列表需要支持条件查询,模糊查询,分页,从代码可以直接看到。

  1. if代码是动态组装条件。

  2. err = query.Offset(offset).Limit(limit).Find(&users).Offset(-1).Limit(-1).Count(&count).Error 这行代码包含了数据列表查询和数据条数。

  3. 有些需要注意的地方是query.Offset(offset).Limit(limit).Find(&users) 用于查询数据列表,

  4. .Offset(-1).Limit(-1).Count(&count)用户查询条数,**Offset(-1)和Limit(-1)**很重要,也是一个小技巧,不加的话会在统计条数后也加上offset和limit,导致查不到条数。 查询结果:

SELECT * FROM `user` LIMIT 10 OFFSET 0;
SELECT count(*) FROM `user`;