单条关联查询

先创建两个关联模型:

// 用户模型
type User struct {
gorm.Model
Username string `gorm:"type:varchar(20);not null;unique"`
Email string `gorm:"type:varchar(64);not null;unique"`
Role string `gorm:"type:varchar(32);not null"`
Active uint8 `gorm:"type:tinyint unsigned;default:1"`
Profile Profile `gorm:"foreignkey:UserID;association_autoupdate:false"`
} // 用户信息模型
type Profile struct {
gorm.Model
UserID uint `gorm:"type:int unsigned;not null;unique"`
Username string `gorm:"type:varchar(20);not null;unique"`
Nickname string `gorm:"type:varchar(64);not null;unique"`
Phone string `gorm:"type:varchar(32)"`
Gender uint8 `gorm:"type:tinyint unsigned;default:0"`
Birthday time.Time `gorm:"type:datetime;default:null"`
Sign string `gorm:"type:varchar(255)"`
Avatar string `gorm:"type:text"`
}

直接查询单条 User 记录

var user User

DB.Debug().First(&user)

这里省略 JSON 序列化输出的过程,直接看输出,类似这样:

{
"ID": 1,
"CreatedAt": "2020-03-11T18:26:13+08:00",
"UpdatedAt": "2020-03-11T18:28:41+08:00",
"DeletedAt": null,
"Username": "test",
"Email": "text@demo.dev",
"Role": "member",
"Active": 1,
"Profile": {
"ID": 0,
"CreatedAt": "001-01-01T00:00:00Z",
"UpdatedAt": "001-01-01T00:00:00Z",
"DeletedAt": null,
"UserID": 0,
"Username": "",
"Nickname": "",
"Phone": "",
"Gender": 0,
"Birthday": "0001-01-01T00:00:00Z",
"Sign": "",
"Avatar": ""
}
}

可以看到,虽然有输出 Profile 字段,但是里面的字段值全为零值,也就是说直接查询 User 并不会默认把关联的 Profile 一同查询出来。

可能有童鞋要问了,没查询 Profile 为什么还会输出空值的 Profile 字段呢?这是因为 JSON 序列化是按照模型的定义自动处理,User 模型中定义了 Profile 字段,如进行关联查询且能查到结果,那么就赋值给 Profile 字段,否则 Profile 依然序列化输出,只不过 Profile 里面的字段全都为空值。

接下来看下如何使用关联查询获取完整的 User 数据:

// 方式一:手动查询关联数据
var user User
// 第一步,查询用户
DB.Debug().First(&user)
// 第二步,查询关联的用户信息
// 注意,Related 方法第二个参数为 Profile 的外键
DB.Debug().Model(&user).Related(&user.Profile, "UserID") // 方式二:也可以使用预加载方式查询关联数据
DB.Debug().Model(&user).Preload("Profile").First(&user)

可以看到,使用预加载方式语法更简练,实际上底层还是2个查询,只不过 gorm 帮我们封装好了,现在可以获取到完整的数据,类似这样:

{
"ID": 1,
"CreatedAt": "2020-03-11T18:26:13+08:00",
"UpdatedAt": "2020-03-11T18:28:41+08:00",
"DeletedAt": null,
"Username": "test",
"Email": "text@demo.dev",
"Role": "member",
"Active": 1,
"Profile": {
"ID": 1,
"CreatedAt": "2020-03-11T18:26:13+08:00",
"UpdatedAt": "2020-03-11T18:26:13+08:00",
"DeletedAt": null,
"UserID": 1,
"Username": "test",
"Nickname": "test",
"Phone": "",
"Gender": 0,
"Birthday": "0001-01-01T00:00:00Z",
"Sign": "",
"Avatar": ""
}
}

列表关联查询

列表的关联查询和单条关联查询类似,不过手动进行列表的关联查询很繁琐,得先查出 User 列表,然后再查询一次 Profile 列表获取对应的数据,最后整合两部分数据。直接使用预加载就很简单了,代码如下:

var users []User

// 使用预加载查询
DB.Debug().Model(&User{}).Preload("Profile").Find(&users)

输出如下:

[
{
"ID": 1,
"CreatedAt": "2020-03-11T18:26:13+08:00",
"UpdatedAt": "2020-03-11T18:28:41+08:00",
"DeletedAt": null,
"Username": "test",
"Email": "text@demo.dev",
"Role": "member",
"Active": 1,
"Profile": {
"ID": 1,
"CreatedAt": "2020-03-11T18:26:13+08:00",
"UpdatedAt": "2020-03-11T18:26:13+08:00",
"DeletedAt": null,
"UserID": 1,
"Username": "test",
"Nickname": "test",
"Phone": "",
"Gender": 0,
"Birthday": "0001-01-01T00:00:00Z",
"Sign": "",
"Avatar": ""
}
},
...
]

gorm 底层使用这两条查询:

SELECT * FROM `user`  WHERE `user`.`deleted_at` IS NULL

SELECT * FROM `profile`  WHERE `profile`.`deleted_at` IS
NULL AND ((`user_id` IN (1,2,3,4,5,6)))

gorm 还在内部把两条查询的数据都整合好了,使用相当方便。

这只是一个简单的预加载应用,更多应用可参考 Gorm官方文档-预加载

小结

预加载在单条关联查询中提供了更简洁的语法,在列表关联查询中不仅解决了关联查询 N + 1 的问题,还自动整合了数据,方便快捷。

到这里,一个简单的预加载查询就完成了,但是可以发现查询输出还有很多瑕疵,如:只查询 User 也会带上空值 Profile,字段名和模型定义的一样都是首字母大写,并且时间格式不友好。

这就衍生出了几个问题:

  • 如何自定义输出结构,只输出指定字段?
  • 如何自定义字段名,并去掉空值字段?
  • 如何自定义时间格式?

下一篇将介绍如何处理查询输出,解决上述问题。

如发现任何问题,欢迎指正,谢谢观看!


参考资料: Gorm官方文档

本文出处:https://www.cnblogs.com/zhenfengxun/

本文链接:https://www.cnblogs.com/zhenfengxun/p/12486325.html

Gorm 预加载及输出处理(一)- 预加载应用的更多相关文章

  1. Gorm 预加载及输出处理(二)- 查询输出处理

    上一篇<Gorm 预加载及输出处理(一)- 预加载应用>中留下的三个问题: 如何自定义输出结构,只输出指定字段? 如何自定义字段名,并去掉空值字段? 如何自定义时间格式? 这一篇先解决前两 ...

  2. Gorm 预加载及输出处理(三)- 自定义时间格式

    前言 Gorm 中 time.Time 类型的字段在 JSON 序列化后呈现的格式为 "2020-03-11T18:26:13+08:00",在 Go 标准库文档 - time 的 ...

  3. 图片预加载和AJAX的图片预加载

    利用js实现图片预加载,加载所需要图片的路径与名称即可,很容易实现,该方法尤其适用预加载大量的图片: <div class="hidden"> <script t ...

  4. HTML5的页面资源预加载技术(Link prefetch)加速页面加载

    不管是浏览器的开发者还是普通web应用的开发者,他们都在做一个共同的努力:让Web浏览有更快的速度感觉.有很多已知的技术都可以让你的网站速度变得更快:使用CSS sprites,使用图片优化工具,使用 ...

  5. 转载:用Jquery实现的图片预加载技术,可以实现有序加载和无序加载!

    一.背景 我们在做页面的时候,从用户体验的角度出发,肯定是希望用户以最快的速度看到完整的页面信息,但在实际情况中经常会遇到些问题. 比如受网速影响,页面加载素材的时间比较长,页面会出现短时间的错乱或者 ...

  6. js原生图片懒加载 或 js原生图片预加载,html标签自定义属性

    使用原声js来实现图片预加载,或图片懒加载,小伙伴们可以根据项目需要来结合vue或者是react来进行修改. 一.什么是图片懒加载或什么是图片预加载 当访问一个页面的时候,先把img元素或是其他元素的 ...

  7. moviepy音视频剪辑:使用VideoFileClip、AudioFileClip和write_videofile、write_audiofile进行音视频的加载和输出

    专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 一.概述 在本地进行音视频处理时,首先要从视频文件 ...

  8. moviepy音视频剪辑:音视频的加载和输出

    专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 一.概述 在本地进行音视频处理时,首先要从视频文件 ...

  9. js图片加载效果(延迟加载+瀑布流加载)

    概述 两种图片加载的效果:一种是遇到图片较多时,带读条效果的加载提示:另一种是根据滑块的位置进行预加载,用户不察觉的情况下,实现瀑布流的加载效果 详细 代码下载:http://www.demodash ...

  10. Hi3559AV100 NNIE开发(7) Ruyistudio 输出mobileface_func.wk与板载运行mobileface_chip.wk输出中间层数据对比

    前面随笔讲了关于NNIE的整个开发流程,并给出了Hi3559AV100 NNIE开发(5)mobilefacenet.wk仿真成功量化及与CNN_convert_bin_and_print_featu ...

随机推荐

  1. 构造函数中可以进行if判断

  2. MOOC(7)- case依赖、读取json配置文件进行多个接口请求-测试类中调用封装的mock(10)

    封装mock后,在单元测试中调用 # -*- coding: utf-8 -*- # @Time : 2020/2/11 8:35 # @File : test_class_10.py.py # @A ...

  3. 微软研究员Eric Horvitz解读 “人工智能百年研究”

    本文翻译自ScienceInsider"A 100-year study of artificial intelligence? Microsoft Research's Eric Horv ...

  4. Markdown快速使用指南

    Markdown 是一种轻量级的标记语言,他简洁.高效,目前被越来越多的写作爱好者,撰稿者广泛使用.Markdown的语法十分简单.常用的标记符号也不超过十个,这种相对于更为复杂的 HTML 标记语言 ...

  5. JS Style Guide_1

    当你在回调函数里要使用函数表达式时,尽量使用箭头函数,比如数组中的 Map.filter.reduce等的回调函数中 [1,2,3].map((x) => { let y = x + 1; re ...

  6. npm(classnames) 更灵活使用类名

    npm install classnames --save import classNames from 'classnames'; const inputCls = classNames({ [st ...

  7. How to Write a README on GitHub

    最近在寫 GitHub 上的 README,發現這個東西好像每個人的寫法都不太一樣,於是稍微整理了一下自己覺得大概要包含哪些內容. Motivation 顧名思義就是簡介一下為什麼會有這個專案,以及這 ...

  8. redis集群配置及python操作

    之前我们分析过喜马拉雅的爬取信息,使用分布式爬取,而且需要修改scrapy-redis的过滤算法为布隆过滤来减少redis内存占用,最后考虑这样还是不一定够,那么redis集群就是更好的一种选择方式了 ...

  9. 无线城域网 WMAN

    无线城域网 WMAN (Wireless Metropolitan Area Network) 1.1.概述 2002 年 4 月通过了 802.16 无线城域网的标准.欧洲的 ETSI 也制订类似的 ...

  10. GDB调试系列之了解GDB

    想要熟练利用GDB进行程序调试,首先要了解什么是GDB. 1. 什么是GDB GDB (the GNU Project Debugger) 是一个可以运行在大多数常见的UNIX架构.Windows.M ...