gorm和gen的区别
在上一篇文章《go-zero主动生成repository文件和测试用例》中,通过自界说的模板生成了go项目中常见的数据库操作方法,那么这里面其实存在一个细节问题,就是查询数据的时候应该利用gorm照旧gen呢?
实际上,Gen是gorm里面的一个工具,或者说是在gorm的基础上做了更进一步的封装。GORM 和 GORM Gen 都是 Go 语言中用于数据库操作的工具,它们在功能和利用方式上存在一些区别。
- GORM 是一个强大且广泛利用的 Go 语言 ORM(对象关系映射)库,它为开发者提供了丰富的数据库操作功能,如创建、读取、更新和删除(CRUD)操作,支持多种数据库范例,像 MySQL、PostgreSQL 等。GORM 以链式调用的方式构建查询,具有较高的机动性,开发者可以根据具体需求动态构建复杂的查询语句。然而,这种机动性也带来了一定的学习资本,特别是在处理复杂查询时,代码大概会变得冗长且难以维护。
- GORM Gen 则是基于 GORM 开发的代码生成工具,它通过生成预界说的查询方法,减少了手动编写数据库操作代码的工作量。GORM Gen 会根据数据库表结构主动生成对应的模型和查询方法,使得代码更加简洁、规范。开发者只需调用这些生成的方法,就可以完成常见的数据库操作,提高了开发服从。但 GORM Gen 的机动性相对较低,对于一些特殊的查询需求,大概必要手动编写额外的代码。
- 总的来说,GORM 适合必要高度机动性和对数据库操作有深入控制的场景,而 GORM Gen 则更适合快速开发和代码规范统一的项目。
gorm官网:https://gorm.io/
gen的用法:https://gorm.io/gen/
利用案例
接下来,我通过一个常见的查询场景来分析应该利用哪种方式。
好比,有一个用户信息表的结构如下:
- CREATE TABLE `user` (
- `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
- `uuid` varchar(255) NOT NULL DEFAULT '' COMMENT 'uuid',
- `user_id` bigint(20) unsigned NOT NULL COMMENT '用户编号',
- `user_name` varchar(255) NOT NULL DEFAULT '' COMMENT '用户名',
- `password` varchar(255) NOT NULL DEFAULT '' COMMENT '密码',
- `name` varchar(255) NOT NULL DEFAULT '' COMMENT '用户姓名',
- `age` tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT '用户年龄',
- `email` varchar(255) NOT NULL DEFAULT '' COMMENT '用户邮箱',
- `address` varchar(255) NOT NULL DEFAULT '' COMMENT '地址',
- `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态:1审核中,2正常,3禁用,4封号',
- `extra` text COMMENT '扩展数据',
- `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '添加时间',
- `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
- `is_deleted` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '是否删除:0未删除,1已删除',
- PRIMARY KEY (`id`) USING BTREE,
- KEY `key_user_id` (`user_id`) USING BTREE
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户信息表';
复制代码 业务场景是,如要根据如下规则对用户信息的列表查询:
- 1、精确匹配(=): id、user_id、status、email;
- 2、模糊匹配(like): user_name、name、address;
- 3、大小匹配(>=和=<,可以兼容between and): age、create_time、update_time;
- 4、in/not in/ != 查询:id、user_id、user_name;
- 5、其它复杂查询
复制代码 在 gozero/internal/svc/service_context.go中界说数据库相关的上下文:
- package svc
- import (
- "context"
- "go-demo-2025/gozero/internal/config"
- "go-demo-2025/gozero/internal/model/dao/query"
- "gorm.io/driver/mysql"
- "gorm.io/gorm"
- )
- type ServiceContext struct {
- Config config.Config
- DB *gorm.DB //gorm的db对象
- Model *query.Query //gorm的gen的query对象
- }
- func NewServiceContext(c config.Config) *ServiceContext {
- db, _ := gorm.Open(mysql.Open(c.Mysql.DataSource), &gorm.Config{
- Logger: newLogger,
- NamingStrategy: schema.NamingStrategy{
- TablePrefix: "", // 表名前缀
- SingularTable: true, // 使用单数表名,启用该选项,会区分 user 和 users 表为两个不同的数据表
- },
- })
- return &ServiceContext{
- Config: c,
- DB: db,
- Model: query.Use(db),
- }
- }
复制代码 查询方法对比
1、利用gorm查询
先从基础的gorm查询开始,不适用Gen的情况下。查询方法代码如下:
- func (r *UserRepo) GetUserList1(queryEqualConditions map[string]interface{}, queryMoreConditions map[string]interface{}, page, pageSize int) (list []*model.User, count int64, err error) {
- m := r.svcCtx.DB.Model(&model.User{})
- querys := m.WithContext(r.ctx).Debug()
- //基础查询条件
- queryEqualConditions["is_deleted"] = 0
- querys = querys.Where(queryEqualConditions)
- //更多查询条件
- if len(queryMoreConditions) > 0 {
- if queryMoreConditions["ids"] != nil {
- querys = querys.Where("id in ?", queryMoreConditions["ids"].([]int64))
- }
- if queryMoreConditions["user_name"] != "" {
- querys = querys.Where("user_name like ?", "%"+queryMoreConditions["user_name"].(string)+"%")
- }
- if queryMoreConditions["name"] != "" {
- querys = querys.Where("name like?", "%"+queryMoreConditions["name"].(string)+"%")
- }
- if queryMoreConditions["address"] != "" {
- querys = querys.Where("address like?", "%"+queryMoreConditions["address"].(string)+"%")
- }
- if queryMoreConditions["age_min"] != 0 {
- querys = querys.Where("age >=?", queryMoreConditions["age_min"].(int64))
- }
- if queryMoreConditions["age_max"] != 0 {
- querys = querys.Where("age <=?", queryMoreConditions["age_max"].(int64))
- }
- if queryMoreConditions["create_time_start"] != "" {
- // 将字符串类型的时间转换为 time.Time 类型
- createTimeStart, err := time.Parse("2006-01-02 15:04:05", queryMoreConditions["create_time_start"].(string))
- if err == nil {
- querys = querys.Where("create_time >=?", createTimeStart)
- }
- }
- if queryMoreConditions["create_time_end"] != "" {
- // 将字符串类型的时间转换为 time.Time 类型
- createTimeEnd, err := time.Parse("2006-01-02 15:04:05", queryMoreConditions["create_time_end"].(string))
- if err == nil {
- querys = querys.Where("create_time <=?", createTimeEnd)
- }
- }
- }
- querys.Limit(pageSize).Offset(page).Find(&list)
- querys.Count(&count)
- return list, count, nil
- }
复制代码 测试用例代码:
- func TestGetUserListDemo1(t *testing.T) {
- reqData := BuildRequestMockData()
- //构造等于的查询条件
- condsEq := make(map[string]interface{})
- if reqData.UserId != 0 {
- condsEq["user_id"] = reqData.UserId
- }
- if reqData.Status != 0 {
- condsEq["status"] = reqData.Status
- }
- if reqData.Email != "" {
- condsEq["email"] = reqData.Email
- }
- //构造其他查询条件
- condsMore := make(map[string]interface{})
- if len(reqData.Ids) > 0 {
- condsMore["ids"] = reqData.Ids //in
- }
- if reqData.UserName != "" { //like
- condsMore["user_name"] = reqData.UserName
- }
- if reqData.Name != "" { //like
- condsMore["name"] = reqData.Name
- }
- if reqData.Address != "" { //like
- condsMore["address"] = reqData.Address
- }
- if reqData.AgeMin != 0 { //>=
- condsMore["age_min"] = reqData.AgeMin
- }
- if reqData.AgeMax != 0 { //<=
- condsMore["age_max"] = reqData.AgeMax
- }
- if reqData.CreateTimeStart != "" { //>=
- condsMore["create_time_start"] = reqData.CreateTimeStart
- }
- if reqData.CreateTimeEnd != "" { //<=
- condsMore["create_time_end"] = reqData.CreateTimeEnd
- }
- //执行查询
- ts := utils.NewTestCtx()
- repo := mysql.NewUserRepo(ts.Ctx, ts.SvcCtx)
- list, count, err := repo.GetUserList1(condsEq, condsMore, 1, 20)
- t.Log("list: ", utils.EchoJson(list))
- t.Log("count: ", count)
- t.Log("error: ", err)
- assert.NoError(t, err)
- }
复制代码 运行效果:

生成的SQL语句:
- SELECT * FROM `user` WHERE (`email` = 'test@125.com' AND `is_deleted` = 0 AND `status` = 1) AND id in (1,2,3) AND user_name like '%zhangsan%' AND name like'%张三%' AND address like'%beijing%' AND age >=10 AND age <=50 AND create_time >='2024-01-01 08:00:00' AND create_time <='2024-01-02 07:59:59' LIMIT 20 OFFSET 1
复制代码 上面的写法中,针对相称查询封装到了一个map中,针对非等查询,在repo中又一次逐一判断,有点繁琐,可以优化如下:
2、利用gorm查询优化
封装一个 ApplyQueryConditions 函数用于处理非即是查询条件:
- // Condition 结构体用于存储操作符和值
- type Condition struct {
- Field string // 字段名
- Operator string // 操作符
- Value interface{} // 值
- }
- // ApplyQueryConditions 函数用于处理非等于查询条件
- func ApplyQueryConditions(query *gorm.DB, conditions []Condition) *gorm.DB {
- for _, cond := range conditions {
- switch cond.Operator {
- case "=":
- query = query.Where(fmt.Sprintf("%s = ?", cond.Field), cond.Value)
- case "!=":
- query = query.Where(fmt.Sprintf("%s !=?", cond.Field), cond.Value)
- case "like":
- query = query.Where(fmt.Sprintf("%s LIKE ?", cond.Field), "%"+cond.Value.(string)+"%")
- case "in":
- query = query.Where(fmt.Sprintf("%s IN ?", cond.Field), cond.Value)
- case ">":
- query = query.Where(fmt.Sprintf("%s > ?", cond.Field), cond.Value)
- case "<":
- query = query.Where(fmt.Sprintf("%s < ?", cond.Field), cond.Value)
- case ">=":
- query = query.Where(fmt.Sprintf("%s >= ?", cond.Field), cond.Value)
- case "<=":
- query = query.Where(fmt.Sprintf("%s <= ?", cond.Field), cond.Value)
- default:
- // 可以根据需要添加更多操作符
- }
- }
- return query
- }
复制代码 然后,查询方法优化如下:
- func (r *UserRepo) GetUserList2(queryEqualConditions map[string]interface{}, queryMoreConditions []Condition, page, pageSize int) (list []*model.User, count int64, err error) {
- m := r.svcCtx.DB.Model(&model.User{})
- querys := m.WithContext(r.ctx).Debug()
- //基础查询条件
- queryEqualConditions["is_deleted"] = 0
- querys = querys.Where(queryEqualConditions)
- //更多查询条件
- if len(queryMoreConditions) > 0 {
- querys = ApplyQueryConditions(querys, queryMoreConditions)
- }
- querys.Limit(pageSize).Offset(page).Find(&list)
- querys.Count(&count)
- return list, count, nil
- }
复制代码 测试用例:
- func TestGetUserListDemo2(t *testing.T) {
- reqData := BuildRequestMockData()
- //构造等于的查询条件
- condsEq := make(map[string]interface{})
- if reqData.UserId != 0 {
- condsEq["user_id"] = reqData.UserId
- }
- if reqData.Status != 0 {
- condsEq["status"] = reqData.Status
- }
- if reqData.Email != "" {
- condsEq["email"] = reqData.Email
- }
- //构造其他查询条件
- condsMore := make([]mysql.Condition, 0)
- if len(reqData.Ids) > 0 {
- condsMore = append(condsMore, mysql.Condition{"id", "in", reqData.Ids})
- }
- if reqData.UserName != "" {
- condsMore = append(condsMore, mysql.Condition{"user_name", "like", reqData.UserName})
- }
- if reqData.Name != "" {
- condsMore = append(condsMore, mysql.Condition{"name", "like", reqData.Name})
- }
- if reqData.Address != "" {
- condsMore = append(condsMore, mysql.Condition{"address", "like", reqData.Address})
- }
- if reqData.AgeMin != 0 {
- condsMore = append(condsMore, mysql.Condition{"age", ">=", reqData.AgeMin})
- }
- if reqData.AgeMax != 0 {
- condsMore = append(condsMore, mysql.Condition{"age", "<=", reqData.AgeMax})
- }
- if reqData.CreateTimeStart != "" {
- createTimeStart, err := time.Parse("2006-01-02 15:04:05", reqData.CreateTimeStart)
- if err == nil {
- condsMore = append(condsMore, mysql.Condition{"create_time", ">=", createTimeStart})
- }
- }
- if reqData.CreateTimeEnd != "" {
- createTimeEnd, err := time.Parse("2006-01-02 15:04:05", reqData.CreateTimeEnd)
- if err == nil {
- condsMore = append(condsMore, mysql.Condition{"create_time", "<=", createTimeEnd})
- }
- }
- //执行查询
- ts := utils.NewTestCtx()
- repo := mysql.NewUserRepo(ts.Ctx, ts.SvcCtx)
- list, count, err := repo.GetUserList2(condsEq, condsMore, 1, 20)
- t.Log("list: ", utils.EchoJson(list))
- t.Log("count: ", count)
- t.Log("error: ", err)
- assert.NoError(t, err)
- }
复制代码 运行效果和上面的是一样的:
- SELECT * FROM `user` WHERE (`email` = 'test@125.com' AND `is_deleted` = 0 AND `status` = 1) AND id IN (1,2,3) AND user_name LIKE '%zhangsan%' AND name LIKE '%张三%' AND address LIKE '%beijing%' AND age >= 10 AND age <= 50 AND create_time >= '2024-01-01 08:00:00' AND create_time <= '2024-01-02 07:59:59' LIMIT 20 OFFSET 1
复制代码 其实,如许封装后,也可以把即是的查询和其他查询放到一起了:
- if reqData.UserId != 0 {
- condsMore = append(condsMore, mysql.Condition{"user_id", "=", reqData.UserId})
- }
- if reqData.Status != 0 {
- condsMore = append(condsMore, mysql.Condition{"status", "=", reqData.Status})
- }
- if reqData.Email != "" {
- condsMore = append(condsMore, mysql.Condition{"email", "=", reqData.Email})
- }
复制代码 以上写法是利用map的情势,长处是可以封装成统一的查询方法,缺点是如果写错了数据表的字段名,在编译阶段是不会报错的,只有运行的时候才会发现字段名不存在,报错Error 1054 (42S22): Unknown column 'idx' in 'where clause'。因此,可以改为利用结构体来查询。
3、利用gorm结构体查询
利用结构体查询的时候,只必要把之前界说的map改为对应的数据表的model的结构体即可。测试用例如许写:
- func TestGetUserListByGormDemo3(t *testing.T) {
- reqData := BuildRequestMockData()
- //构造等于的查询条件
- condsEq := &model.User{} //User表的Model的结构体
- if reqData.Status != 0 {
- condsEq.Status = reqData.Status
- }
- if reqData.Email != "" {
- condsEq.Email = reqData.Email
- }
- //构造其他查询条件(暂未找到如何替换为结构体的方式)
- condsMore := make([]mysql.Condition, 0)
- if len(reqData.Ids) > 0 {
- condsMore = append(condsMore, mysql.Condition{"id", "in", reqData.Ids})
- }
- //执行查询
- ts := utils.NewTestCtx()
- repo := mysql.NewUserRepo(ts.Ctx, ts.SvcCtx)
- list, count, err := repo.GetUserListByGorm3(condsEq, condsMore, 1, 20)
- }
复制代码 通过上面的写法,可以确定condsEq.Status 一定是一个存在的字段。在查询方法中,通报的参数范例也改为queryEqualConditions *model.User:
- func (r *UserRepo) GetUserListByGorm3(queryEqualConditions *model.User, queryMoreConditions []Condition, page, pageSize int) (list []*model.User, count int64, err error) {
- m := r.svcCtx.DB.Model(&model.User{})
- querys := m.WithContext(r.ctx).Debug()
- //基础查询条件
- queryEqualConditions.IsDeleted = 1
- querys = querys.Where(queryEqualConditions)
- //更多查询条件
- if len(queryMoreConditions) > 0 {
- querys = ApplyQueryConditions(querys, queryMoreConditions)
- }
- querys.Limit(pageSize).Offset(page).Find(&list)
- querys.Count(&count)
- return list, count, nil
- }
复制代码
- SELECT * FROM `user` WHERE (`user`.`email` = 'test@125.com' AND `user`.`status` = 1 AND `user`.`is_deleted` = 1) AND 0 IN (1,2,3) LIMIT 20 OFFSET 1
复制代码 但是,如许写会存在以下几个问题:
- 对于非即是的查询,如今我还没找到怎么利用结构体赋值,但依然可以利用上面的map对于非等条件的赋值;
- 如果给Model结构体的某个字段赋值为0或者空字符串,查询语句会忽略此字段,因为Model结构体的初始值对于int范例就是0,对于string范例就是空字符串。在map中不存在这个问题。 验证如下:我把上面的Status写死为0,把Email写死为空字符串:
- //构造等于的查询条件
- condsEq := &model.User{}
- if reqData.Status != 0 {
- condsEq.Status = 0 //reqData.Status
- }
- if reqData.Email != "" {
- condsEq.Email = "" //reqData.Email
- }
复制代码 查询的语句就会忽略这两个字段:
- SELECT * FROM `user` WHERE `user`.`is_deleted` = 1 AND id IN (1,2,3) LIMIT 20 OFFSET 1
复制代码 对于上面的问题,有个间接的办法就是:
- 对于int范例,只管避免利用0,对于状态“是”和“否”,不利用1和0,而利用1和2。
- 对于string范例,可以自界说一个业务上用不到的字符串,例如“my_empty_str”。
以上,就是利用gorm查询的方法传值的差别和对比。关于gorm的更多查询方法参考:https://gorm.io/zh_CN/docs/query.html
接下来,利用Gen的方式来试试查询语句怎么写。
4、利用Gen查询
查询方法的代码如下:
- func (r *UserRepo) GetUserListByGen1(queryEqualConditions map[string]interface{}, queryMoreConditions map[string]interface{}, page, pageSize int) (list []*model.User, count int64, err error) {
- m := r.svcCtx.Model.User
- querys := m.WithContext(r.ctx).Debug().Where(m.IsDeleted.Eq(0))
- //基础查询条件
- querys = querys.Where(field.Attrs(queryEqualConditions))
- //更多查询条件
- if len(queryMoreConditions) > 0 {
- if queryMoreConditions["ids"] != nil {
- querys = querys.Where(m.ID.In(queryMoreConditions["ids"].([]int64)...))
- }
- if queryMoreConditions["user_name"] != "" {
- querys = querys.Where(m.UserName.Like("%" + queryMoreConditions["user_name"].(string) + "%"))
- }
- if queryMoreConditions["age_min"] != 0 {
- querys = querys.Where(m.Age.Gte(queryMoreConditions["age_min"].(int64)))
- }
- if queryMoreConditions["age_max"] != 0 {
- querys = querys.Where(m.Age.Lte(queryMoreConditions["age_max"].(int64)))
- }
- }
- offset := (page - 1) * pageSize
- limit := pageSize
- res, count, err := querys.Order(m.ID.Desc()).FindByPage(offset, limit)
- if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
- logx.WithContext(r.ctx).Errorf("Failed to get list: %v", err)
- return nil, 0, err
- }
- return res, count, nil
- }
复制代码 测试用例的代码写法:
- func TestGetUserListByGenDemo1(t *testing.T) {
- reqData := BuildRequestMockData()
- //构造等于的查询条件
- condsEq := make(map[string]interface{})
- if reqData.UserId != 0 {
- condsEq["user_id"] = reqData.UserId
- }
- if reqData.Status != 0 {
- condsEq["status"] = reqData.Status
- }
- if reqData.Email != "" {
- condsEq["email"] = reqData.Email
- }
- //构造其他查询条件
- condsMore := make(map[string]interface{})
- if len(reqData.Ids) > 0 {
- condsMore["ids"] = reqData.Ids //in
- }
- if reqData.UserName != "" { //like
- condsMore["user_name"] = reqData.UserName
- }
- if reqData.AgeMin != 0 { //>=
- condsMore["age_min"] = reqData.AgeMin
- }
- if reqData.AgeMax != 0 { //<=
- condsMore["age_max"] = reqData.AgeMax
- }
- //执行查询
- ts := utils.NewTestCtx()
- repo := mysql.NewUserRepo(ts.Ctx, ts.SvcCtx)
- list, count, err := repo.GetUserListByGen1(condsEq, condsMore, 1, 20)
- t.Log("list: ", utils.EchoJson(list))
- t.Log("count: ", count)
- t.Log("error: ", err)
- assert.NoError(t, err)
- }
复制代码 执行后的语句和上面没有区别:

- SELECT * FROM `user` WHERE `user`.`is_deleted` = 0 AND (`email` = 'test@125.com' AND `status` = 1) AND `user`.`id` IN (1,2,3) AND `user`.`user_name` LIKE '%zhangsan%' AND `user`.`age` >= 10 AND `user`.`age` <= 50 ORDER BY `user`.`id` DESC LIMIT 20
复制代码 和上面利用gorm查询,最大的区别:
- 把m := r.svcCtx.DB.Model(&model.User{}) 换成了 m := r.svcCtx.Model.User
- 把querys = querys.Where(queryEqualConditions) 换成了 querys = querys.Where(field.Attrs(queryEqualConditions))
- 这里的 querys.Order(m.ID.Desc()).FindByPage(offset, limit) 方法直接返回的就是三个参数:res, count, err
你可以查看Gen生成的源代码了解其更多方法:
上面利用Gen的查询条件依然是封装了map,我仍然希望可以大概通过结构体属性来访问查询条件,如许如果我的字段名写错了,就可以在编译阶段报错。因此,继承优化为下面的写法。
5、利用Gen查询优化
由于在Gen的查询方法中,对于非等查询不太好封装成统一的方法,因此,我决定在repo层直接吸取调用方(好比:logic层或测试用例处)通报来的req变量,然后针对每一类查询条件逐一处理。如许看起来代码也比力工整。
先从go-zero的api文件开始,界说必要查询用户列表的条件的结构体:
- type UserListRequest {
- UserId int64 `json:"user_id,optional"` // 用户id,eq查询
- Status int64 `json:"status,optional"` // 用户状态,eq查询
- Email string `json:"email,optional"` // 邮箱,eq查询
- Ids string `json:"ids,optional"` // 多个id用逗号分隔,in查询
- UserName string `json:"user_name,optional"` // 用户名,like查询
- AgeMin int64 `json:"age_min,optional"` // 年龄,>=
- AgeMax int64 `json:"age_max,optional"` // 年龄,<=
- Page int64 `json:"page,optional,default=1"`
- PageSize int64 `json:"page_size,optional,default=10"`
- }
复制代码 然后,在 gozero/internal/logic/admin/user_list_logic.go 中,把请求参数 req *types.UserListRequest 直接通报到repo层:
- func (l *UserListLogic) UserList(req *types.UserListRequest) (resp []*types.UserListResponse, err error) {
- //根据前端传来的参数req查询用户数据列表
- userModelList, count, err := l.userRepo.GetUserListByGen2(req)
- if err != nil {
- return nil, err
- }
- //定义返回的结构体
- userListResp := make([]*types.UserListResponse, 0)
- //如果查询到的结果为空,直接返回预定义的空数据
- if count == 0 {
- return userListResp, nil
- }
- //二次处理userModelList,转换为前端需要的结构体
- // todo...
- fmt.Println(userModelList)
- return userListResp, nil
- }
复制代码 在repo层,必要根据前端传来的req请求参数,封装出一个公用的查询条件,如允许以给其他查询列表和总数之类的方法复用。代码路径:gozero/internal/repo/mysql/user_repo.go
- // 构建查询用户数据的条件
- func (r *UserRepo) BuildQueryUserListCondition(req *types.UserListRequest) (query.IUserDo, error) {
- m := r.svcCtx.Model.User
- querys := m.WithContext(r.ctx).Debug().Where(m.IsDeleted.Eq(0))
- if req.UserId > 0 {
- querys = querys.Where(m.ID.Eq(req.UserId)) //eq查询
- }
- if req.Status > 0 {
- querys = querys.Where(m.Status.Eq(req.Status)) //eq查询
- }
- if req.Email != "" {
- querys = querys.Where(m.Email.Eq(req.Email)) //eq查询
- }
- if req.Ids != "" {
- idsSlice := utils.CommaSeparatedStringToInt64Slice(req.Ids)
- if len(idsSlice) > 0 {
- querys = querys.Where(m.ID.In(idsSlice...)) //in查询
- }
- }
- if req.UserName != "" {
- querys = querys.Where(m.UserName.Like("%" + req.UserName + "%")) //like查询
- }
- if req.AgeMin > 0 {
- querys = querys.Where(m.Age.Gte(req.AgeMin)) //>=查询
- }
- if req.AgeMax > 0 {
- querys = querys.Where(m.Age.Lte(req.AgeMax)) //<=查询
- }
- return querys, nil
- }
复制代码 然后,在查询方法里面调用上面的查询条件,以及后续的查询逻辑:
- func (r *UserRepo) GetUserListByGen2(req *types.UserListRequest) (list []*model.User, count int64, err error) {
- m := r.svcCtx.Model.User
- querys, err := r.BuildQueryUserListCondition(req)
- if err != nil {
- return nil, 0, err
- }
- limit := int(req.PageSize)
- offset := (int(req.Page) - 1) * limit
- res, count, err := querys.Order(m.ID.Desc()).FindByPage(offset, limit)
- if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
- logx.WithContext(r.ctx).Errorf("Failed to get list: %v", err)
- return nil, 0, err
- }
- return res, count, nil
- }
复制代码 接下来,启动服务,用一个全都满足的条件查询试一下:
打印的SQL语句如下:
- SELECT * FROM `user` WHERE `user`.`is_deleted` = 0 AND `user`.`user_id` = 1001004 AND `user`.`status` = 2 AND `user`.`email` = 'nieqingchun@test.com' AND `user`.`id` IN (3,4,5) AND `user`.`user_name` LIKE '%nie%' AND `user`.`age` >= 15 AND `user`.`age` <= 30 ORDER BY `user`.`id` DESC LIMIT 10
复制代码 在测试用例中的测试效果:
- func TestGetUserListByGenDemo2(t *testing.T) {
- reqData := &types.UserListRequest{
- UserId: 1001004,
- Status: 2,
- Email: "nieqingchun@test.com",
- Ids: "3,4,5",
- UserName: "nie",
- AgeMin: 15,
- AgeMax: 30,
- Page: 1,
- PageSize: 10,
- }
- //执行查询
- ts := utils.NewTestCtx()
- repo := mysql.NewUserRepo(ts.Ctx, ts.SvcCtx)
- list, count, err := repo.GetUserListByGen2(reqData)
- t.Log("list: ", utils.EchoJson(list))
- t.Log("count: ", count)
- t.Log("error: ", err)
- assert.NoError(t, err)
- }
复制代码
综上对比,建议利用如许的方式,因为BuildQueryUserListCondition() 这里封装的查询条件可以给其他方法复用,而且,所有的查询条件的字段都是通过结构体的情势处理的,避免了map中字段写错编译也不报错的情况。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |