gorm Preload与Joins带条件查询--闭坑指南与示例

  • 一. Preload与Joins的区别
  • 二. 使用示例
    • 1. Preload
      • 1.1 Preload 带条件查询
    • 2 Joins
      • 2.1 Joins 带条件查询
      • 2.2 Joins 模糊查询
      • 2.3 使Joins支持一对多关系的查询
      • 2.4 Joins方法的错误示范

一. Preload与Joins的区别

  • Preload方法是用来加载关联字段(belongTomany2manyhasOnehasMany)的数据的。
  • gorm中的Joins方法仅适用的查询,无法加载关联字段内容。并且,gorm原生的方法只支持一对一关系(has one, belongs to)。

二. 使用示例

示例中用到的结构体如下

type Child struct {gorm.ModelChildName string `gorm:"column:child_name;unique"`Toys      []Toy  `gorm:"foreignKey:ChildId"`
}
func (Child) TableName() string {return "child"
}type Toy struct {gorm.ModelName    string `gorm:"column:name"`ChildId uint   `gorm:"column:child_id"`Child   *Child `gorm:"foreignKey:ChildId"`
}
func (Toy) TableName() string {return "toy"
}

并生成以下数据

var children = []Child{{ChildName: "刘涛",Toys: []Toy{{Name: "纸飞机"},{Name: "小火车"},},},{ChildName: "王斌",Toys: []Toy{{Name: "玩具兵"},},},
}
db.Create(&children)

1. Preload

1.1 Preload 带条件查询

举个例子:有个活动需要带所有孩子都参加,但是每个孩子都只能带名为纸飞机的玩具。
使用如下查询方法:

var children []Child
db.Preload("Toys", db.Where(&Toy{Name: "纸飞机"})).Find(&children)
//也可以写成
//db.Preload("Toys", "name = ?", "纸飞机").Find(&children)

等同于sql语句

SELECT * FROM "toy" WHERE "toy"."child_id" IN (1,2) AND name =  '纸飞机' AND "toy"."deleted_at" IS NULL;
SELECT * FROM "child" WHERE "child"."deleted_at" IS NULL;

输出结果转为json(为了易于查看,省略了一些不必要的字段):

[{"ID": 1,"ChildName": "刘涛","Toys": [{"ID": 1,"ChildId": 1,"Name": "纸飞机"}]},{"ID": 2,"ChildName": "王斌","Toys": []}
]

可以看到,王斌小朋友也出现在了查询结果中,但是他的"Toys”是空的。因为你的查询条件只允许小朋友们带纸飞机。


2 Joins

2.1 Joins 带条件查询

因为joins只支持has onebelongs to,所有这里的例子换个方向:查询哪些玩具是属于刘涛的。
查询示例如下:

var toys []Toy
//注意where中的表别名一定要加双引号
db.Joins("Child").Where("\"Child\".child_name = ?", "刘涛").Find(&toys)//也可以写成这样,这里是不需要双引号的
db.Debug().Joins("Child").Clauses(clause.Eq{Column: "Child.child_name",Value:  "刘涛",
}).Find(&toys)

等同于sql:

SELECT "toy"."id","toy"."created_at","toy"."updated_at","toy"."deleted_at","toy"."child_id","toy"."name","Child"."id" AS "Child__id","Child"."created_at" AS "Child__created_at","Child"."updated_at" AS "Child__updated_at","Child"."deleted_at" AS "Child__deleted_at","Child"."child_name" AS "Child__child_name" FROM "toy" LEFT JOIN "child" "Child" ON "toy"."child_id" = "Child"."id" AND "Child"."deleted_at" IS NULL WHERE "Child".child_name = '刘涛' AND "toy"."deleted_at" IS NULL

主要是这断话:LEFT JOIN "child" "Child",gorm自动給表起了一个别名Child

查询结果:

[{"ID": 1,"CreatedAt": "2022-11-09T19:51:38.008533+08:00","UpdatedAt": "2022-11-09T19:51:38.008533+08:00","DeletedAt": null,"ChildId": 1,"Child": {"ID": 1,"CreatedAt": "2022-11-09T19:51:38.006354+08:00","UpdatedAt": "2022-11-09T19:51:38.006354+08:00","DeletedAt": null,"ChildName": "刘涛","Toys": null},"Name": "纸飞机"},{"ID": 2,"CreatedAt": "2022-11-09T19:51:38.008533+08:00","UpdatedAt": "2022-11-09T19:51:38.008533+08:00","DeletedAt": null,"ChildId": 1,"Child": {"ID": 1,"CreatedAt": "2022-11-09T19:51:38.006354+08:00","UpdatedAt": "2022-11-09T19:51:38.006354+08:00","DeletedAt": null,"ChildName": "刘涛","Toys": null},"Name": "小火车"}
]

2.2 Joins 模糊查询

模糊查询最省力的方法是使用子句构造器,其它类似的方法就不展示了:

//查询拥有‘汽车’玩具的孩子们
db = db.Joins("Toys").Clauses(clause.Like{Column: "Toys.name",Value:  "%" + "汽车" + "%",}).Find(&children)

2.3 使Joins支持一对多关系的查询

这个方法其实也支持多对多关系,和sql语法是原理是一样的。
例子:查询有纸飞机玩具的孩子们,没有的孩子不展示。

var children []Child
db.Table(fmt.Sprintf("%v AS t1", Child{}.TableName())).Joins(fmt.Sprintf("LEFT JOIN %v AS t2 on t1.id =t2.child_id ", Toy{}.TableName())).Where("t2.name = ?", "纸飞机").Find(&children)

等同于sql语句

SELECT "t1"."id","t1"."created_at","t1"."updated_at","t1"."deleted_at","t1"."child_name" FROM child AS t1 left join toy t2 on t1.id =t2.child_id  WHERE t2.name = '纸飞机' AND "t1"."deleted_at" IS NULL

查询结果

[{"ID": 1,"CreatedAt": "2022-11-09T19:51:38.006354+08:00","UpdatedAt": "2022-11-09T19:51:38.006354+08:00","DeletedAt": null,"ChildName": "刘涛","Toys": null}
]

可以看到,查询结果没问题,但是Toys是空的。加一个Preload方法就行了

db.Preload("Toys").Table(fmt.Sprintf("%v AS t1", Child{}.TableName())).Joins(fmt.Sprintf("LEFT JOIN %v AS t2 on t1.id =t2.child_id ", Toy{}.TableName())).Where("t2.name = ?", "纸飞机").Find(&children)

输出结果

[{"ID": 1,"CreatedAt": "2022-11-09T19:51:38.006354+08:00","UpdatedAt": "2022-11-09T19:51:38.006354+08:00","DeletedAt": null,"ChildName": "刘涛","Toys": [{"ID": 1,"CreatedAt": "2022-11-09T19:51:38.008533+08:00","UpdatedAt": "2022-11-09T19:51:38.008533+08:00","DeletedAt": null,"ChildId": 1,"Child": null,"Name": "纸飞机"},{"ID": 2,"CreatedAt": "2022-11-09T19:51:38.008533+08:00","UpdatedAt": "2022-11-09T19:51:38.008533+08:00","DeletedAt": null,"ChildId": 1,"Child": null,"Name": "小火车"}]}
]

2.4 Joins方法的错误示范

需要注意的是,Joins方法的查询条件需要放在Where方法中。
但是很多人会和Preload方法混淆,写成这样

//错误示例1
db.Joins("Child", db.Where(&Child{ChildName: "刘涛"})).Find(&toys)
//错误示例2
db.Joins("Child", "Child.child_name = '刘涛'").Find(&toys)
  • 错误示例1 查询出来的玩具兵也变成刘涛的了,完全不对;
    官方文档 中虽然有介绍到这个方法,但是实际使用中意义不明,而且还存在bug。

  • 错误示例2 完全无意义的查询方法。

    [{"ID": 1,"CreatedAt": "2022-11-09T19:51:38.008533+08:00","UpdatedAt": "2022-11-09T19:51:38.008533+08:00","DeletedAt": null,"ChildId": 1,"Child": {"ID": 1,"CreatedAt": "2022-11-09T19:51:38.006354+08:00","UpdatedAt": "2022-11-09T19:51:38.006354+08:00","DeletedAt": null,"ChildName": "刘涛","Toys": null},"Name": "纸飞机"},{"ID": 2,"CreatedAt": "2022-11-09T19:51:38.008533+08:00","UpdatedAt": "2022-11-09T19:51:38.008533+08:00","DeletedAt": null,"ChildId": 1,"Child": {"ID": 1,"CreatedAt": "2022-11-09T19:51:38.006354+08:00","UpdatedAt": "2022-11-09T19:51:38.006354+08:00","DeletedAt": null,"ChildName": "刘涛","Toys": null},"Name": "小火车"},{"ID": 3,"CreatedAt": "2022-11-09T19:51:38.008533+08:00","UpdatedAt": "2022-11-09T19:51:38.008533+08:00","DeletedAt": null,"ChildId": 2,"Child": {"ID": 2,"CreatedAt": "2022-11-09T19:51:38.006354+08:00","UpdatedAt": "2022-11-09T19:51:38.006354+08:00","DeletedAt": null,"ChildName": "王斌","Toys": null},"Name": "玩具兵"}
    ]
    

gorm Preload与Joins带条件查询--闭坑指南与示例相关推荐

  1. bootstrap-table使用 带条件查询翻页及数据更新的问题。

    bootstrap-table很容易上手,方便易用.自己在使用bootstrap-table时查询的参数如下: { limit: params.limit,     //页面大小 offset: pa ...

  2. Mybatis-plus :分页带条件查询

    StudentController @ApiOperation("分页带条件查询学生信息")@GetMapping("/getStudentByOpr/{pageNo}/ ...

  3. vue+node多条件查询 分页_SpringBoot+JPA框架分页、带条件查询等操作

    前言 最近研究JPA框架,初学SpringBoot时也简单学过,但是不是很深入,所以这次主要是说一些进阶且常用.实用的操作! 前置准备 创建两张表或者让JPA自动建表,任意选择!学生表 package ...

  4. vue 前端项目带条件查询的分页列表开发实战

    一 添加医院设置路由 修改文件 E:\vue-sdgt\src\router\index.js {path: '/hospital',component: Layout,redirect: '/hos ...

  5. MyBatisPlus条件构造器带条件查询selectList使用

    场景 项目搭建专栏: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/column/info/37194 基础搭建: https://blog.csdn.net/B ...

  6. mysql带条件查询,联表查询

    ---恢复内容开始--- 1,用于设定所select出来的数据是否允许出现重复行(完全相同的数据行) all:允许出现--默认不写就是All(允许的). distinct:不允许出现--就是所谓的&q ...

  7. mysql连表条件查询_mysql带条件查询,联表查询

    ---恢复内容开始---mysql 1,用于设定所select出来的数据是否容许出现重复行(彻底相同的数据行)sql all:容许出现--默认不写就是All(容许的).spa distinct:不容许 ...

  8. java中pageInfo分页带条件查询+查询条件的回显

    代码如下:解析在下边 <%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %&g ...

  9. mySql中count带条件查询

    方法一: SELECTcount(t.command_name = 'UNLOCK'OR NULL) unlockFrequency FROM 表 t 方法二: select count(t.comm ...

最新文章

  1. python使用HanLP进行句法分析实战
  2. Huffman 编码压缩算法
  3. Web Magic 总体架构
  4. 页面加载完毕执行多个JS函数
  5. keil c语言 位域,联合体位域在keil c遇到的问题怎样解决?
  6. 图解TCP/IP第一章学习
  7. redis 分布式锁 看门狗_redis分布式锁原理及实现
  8. 本机未装Oracle数据库时Navicat for Oracle 报错:Cannot create oci environment 原因分析及解决方案
  9. naivcat 破解安装教程(永久)
  10. Java面试题及答案2019_一般JAVA面试题及答案解析2019
  11. 计算机的显卡控制面板在哪里,nvidia控制面板在哪,详细教您如何进入英伟达控制面板...
  12. adams做动态静力学分析(牛头刨床为例)机械原理课设(完整)
  13. 液压控制系统的simulink搭建
  14. IE首页被篡改(手动修复)
  15. 使用vue扫描扫描仪图像
  16. pdf文件怎么转换成图片
  17. SRAM随机存储器的特点及结构
  18. 微型计算机开不了机,联想C225微型计算机怎么开不起机呢?
  19. 《python》002 网络爬虫 -0A 基础
  20. PHP isset()与empty()

热门文章

  1. 台湾国立大学机器学习基石.听课笔记(第六讲): 一般化(举一反三)的理论
  2. flex和php,开始使用flex和weborb对于PHP
  3. 修复损坏的zip文件
  4. 手机怎么设置每日喝水提醒
  5. nginx负载均衡原理
  6. 目前比较火的赚钱自媒体平台有哪些,平台调性是什么?
  7. host文件 - 学习/实践
  8. 是什么挡了印刷业ERP的发展之路?
  9. 0基础能学漫画么?漫画零基础入门教程!
  10. UML 用例图中include,extends,uses的区别