gorm 一对多关系 以及预加载的用法

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介: gorm 一对多关系 以及预加载的用法

一对多关系的介绍

这里女神表里面有多个舔狗,就是一对多has many关系

并且舔狗表里面包含Info信息表,是has one关系

type GirlGOD struct {
  gorm.Model
  Name string
  Dog  []Dog
}
type Dog struct {
  gorm.Model
  Name      string
  GirlGodID uint
  Info      Info
}
type Info struct {
  gorm.Model
  Age   int
  Money int
  DogID uint
}
func main() {
  db, _ := gorm.Open(mysql.New(mysql.Config{DSN: "root:123456@tcp(127.0.0.1:3306)/gormDB?charset=utf8mb4&parseTime=True&loc=Local"}), &gorm.Config{})
  db.AutoMigrate(&GirlGOD{}, &Dog{}, &Info{})
  info1 := Info{
    Age:   1,
    Money: 1,
  }
  info2 := Info{
    Age:   2,
    Money: 2,
  }
  dog1 := Dog{
    Name: "dog1",
    Info: info1,
  }
  dog2 := Dog{
    Name: "dog2",
    Info: info2,
  }
  girl1 := GirlGOD{
    Name: "girl1",
    Dogs:  []Dog{dog1},
  }
  girl2 := GirlGOD{
    Name: "girl2",
    Dogs:  []Dog{dog2},
  }
  db.Debug().Create(&girl1)
  db.Debug().Create(&girl2)
}

预加载

Preload预加载

Preload 在一个单独查询中加载关联数据。

不使用预加载

查不出关联的舔狗的信息

func main() {
  db, _ := gorm.Open(mysql.New(mysql.Config{DSN: "root:123456@tcp(127.0.0.1:3306)/gormDB?charset=utf8mb4&parseTime=True&loc=Local"}), &gorm.Config{})
  db.AutoMigrate(&GirlGOD{}, &Dog{}, &Info{})
  var girls []GirlGOD
  db.Debug().Find(&girls)
  fmt.Println(girls)
  for _, v := range girls {
    for i := range v.Dogs {
      fmt.Println(v.Name, v.Dogs[i].Name, v.Dogs[i].Info.Money)
    }
  }
}
2022/05/15 22:53:29 C:/Users/68725/Desktop/leetcode/main.go:32
[42.024ms] [rows:2] SELECT * FROM `girl_gods` WHERE `girl_gods`.`deleted_at` IS NULL
[{{1 2022-05-15 22:43:14.714 +0800 CST 2022-05-15 22:43:14.714 +0800 CST {0001-01-01 00:00:00 +0000 UTC false}} girl1 []} {{2 2022-05-15 22:43:14.756 +0800 CST 2022-05-15 22:43:14.756 +0800 CST {0001-01-01 00:00:00 +0000 UTC false}} girl2 []}]

使用预加载

查出与girlgod关联的dog表的信息,但是与dog表关联的info表信息没有

func main() {
  db, _ := gorm.Open(mysql.New(mysql.Config{DSN: "root:123456@tcp(127.0.0.1:3306)/gormDB?charset=utf8mb4&parseTime=True&loc=Local"}), &gorm.Config{})
  db.AutoMigrate(&GirlGOD{}, &Dog{}, &Info{})
  var girls []GirlGOD
  db.Debug().Preload("Dogs").Find(&girls)
  fmt.Println(girls)
  for _, v := range girls {
    for i := range v.Dogs {
      fmt.Println(v.Name, v.Dogs[i].Name, v.Dogs[i].Info.Money)
    }
  }
}
2022/05/15 22:54:22 C:/Users/68725/Desktop/leetcode/main.go:32
[0.651ms] [rows:2] SELECT * FROM `dogs` WHERE `dogs`.`girl_god_id` IN (1,2) AND `dogs`.`deleted_at` IS NULL
2022/05/15 22:54:22 C:/Users/68725/Desktop/leetcode/main.go:32
[49.459ms] [rows:2] SELECT * FROM `girl_gods` WHERE `girl_gods`.`deleted_at` IS NULL
[{{1 2022-05-15 22:43:14.714 +0800 CST 2022-05-15 22:43:14.714 +0800 CST {0001-01-01 00:00:00 +0000 UTC false}} girl1 [{{1 2022-05-15 22:43:14.752 +0800 CST 2022-05-15 22:43:14.752 +0800 CST {0001-01-01 00:00:00 +0000 UTC false}} dog1 1 {{0 0001-01-01 00:00:00 +0000 UTC 0001-01-01 00:00:00 +0000 UTC {0001-01-01 00:00:00 +0000 UTC false}} 0 0 0}}]} {{2 2022-05-15 22:43:14.756 +0800 CST 2022-05-15 22:43:14.756 +0800 CST {0001-01-01 00:00:00 +0000 UTC false}} girl2 [{{2 2022-05-15 22:43:14.757 +0800 CST 2022-05-15 22:43:14.757 +0800 CST {0001-01-01 00:00:00 +0000 UTC false}} dog2 2 {{0 0001-01-01 00:00:00 +0000 UTC 0001-01-01 00:00:00 +0000 UTC {0001-01-01 00:00:00 +0000 UTC false}} 0 0 0}}]}]
girl1 dog1 0
girl2 dog2 0
func main() {
  db, _ := gorm.Open(mysql.New(mysql.Config{DSN: "root:123456@tcp(127.0.0.1:3306)/gormDB?charset=utf8mb4&parseTime=True&loc=Local"}), &gorm.Config{})
  db.AutoMigrate(&GirlGOD{}, &Dog{}, &Info{})
  var girls []GirlGOD
  db.Debug().Preload("Dogs.Info").Preload("Dogs").Find(&girls)
  fmt.Println(girls)
  for _, v := range girls {
    for i := range v.Dogs {
      fmt.Println(v.Name, v.Dogs[i].Name, v.Dogs[i].Info.Money)
    }
  }
}

使用链式预加载

将与girlgod关联的dog表的信息,dog表与info表关联的信息都查出来

2022/05/15 22:55:26 C:/Users/68725/Desktop/leetcode/main.go:32
[0.000ms] [rows:2] SELECT * FROM `infos` WHERE `infos`.`dog_id` IN (1,2) AND `infos`.`deleted_at` IS NULL
2022/05/15 22:55:26 C:/Users/68725/Desktop/leetcode/main.go:32
[1.531ms] [rows:2] SELECT * FROM `dogs` WHERE `dogs`.`girl_god_id` IN (1,2) AND `dogs`.`deleted_at` IS NULL
2022/05/15 22:55:26 C:/Users/68725/Desktop/leetcode/main.go:32
[44.470ms] [rows:2] SELECT * FROM `girl_gods` WHERE `girl_gods`.`deleted_at` IS NULL
[{{1 2022-05-15 22:43:14.714 +0800 CST 2022-05-15 22:43:14.714 +0800 CST {0001-01-01 00:00:00 +0000 UTC false}} girl1 [{{1 2022-05-15 22:43:14.752 +0800 CST 2022-05-15 22:43:14.752 +0800 CST {0001-01-01 00:00:00 +0000 UTC false}} dog1 1 {{1 2022-05-15 22:43:14.753 +0800 CST 2022-05-15 22:43:14.753 +0800 CST {0001-01-01 00:00:00 +0000 UTC false}} 1 1 1}}]} {{2 2022-05-15 22:43:14.756 +0800 CST 2022-05-15 22:43:14.756 +0800 CST {0001-01-01 00:00:00 +0000 UTC false}} girl2 [{{2 2022-05-15 22:43:14.757 +0800 CST 2022-05-15 22:43:14.757 +0800 CST {0001-01-01 00:00:00 +0000 UTC false}} dog2 2 {{2 2022-05-15 22:43:14.757 +0800 CST 2022-05-15 22:43:14.757 +0800 CST {0001-01-01 00:00:00 +0000 UTC false}} 2 2 2}}]}]
girl1 dog1 1
girl2 dog2 2

条件预加载

func main() {
  db, _ := gorm.Open(mysql.New(mysql.Config{DSN: "root:123456@tcp(127.0.0.1:3306)/gormDB?charset=utf8mb4&parseTime=True&loc=Local"}), &gorm.Config{})
  db.AutoMigrate(&GirlGOD{}, &Dog{}, &Info{})
  var girls []GirlGOD
  db.Debug().Preload("Dogs.Info", "money>0").Preload("Dogs", "name=?", "dog2").Find(&girls)
  fmt.Println(girls)
  for _, v := range girls {
    for i := range v.Dogs {
      fmt.Println(v.Name, v.Dogs[i].Name, v.Dogs[i].Info.Money)
    }
  }
}
2022/05/15 22:56:47 C:/Users/68725/Desktop/leetcode/main.go:32
[1.509ms] [rows:1] SELECT * FROM `infos` WHERE `infos`.`dog_id` = 2 AND money>0 AND `infos`.`deleted_at` IS NULL
2022/05/15 22:56:47 C:/Users/68725/Desktop/leetcode/main.go:32
[1.509ms] [rows:1] SELECT * FROM `dogs` WHERE `dogs`.`girl_god_id` IN (1,2) AND name='dog2' AND `dogs`.`deleted_at` IS NULL
2022/05/15 22:56:47 C:/Users/68725/Desktop/leetcode/main.go:32
[42.171ms] [rows:2] SELECT * FROM `girl_gods` WHERE `girl_gods`.`deleted_at` IS NULL
[{{1 2022-05-15 22:43:14.714 +0800 CST 2022-05-15 22:43:14.714 +0800 CST {0001-01-01 00:00:00 +0000 UTC false}} girl1 []} {{2 2022-05-15 22:43:14.756 +0800 CST 2022-05-15 22:43:14.756 +0800 CST {0001-01-01 00:00:00 +0000 UTC false}} girl2 [{{2 2022-05-15 22:43:14.757 +0800 CST 2022-05-15 22:43:14.757 +0800 CST {0001-01-01 00:00:00 +0000 UTC false}} dog2 2 {{2 2022-05-15 22:43:14.757 +0800 CST 2022-05-15 22:43:14.757 +0800 CST {0001-01-01 00:00:00 +0000 UTC false}} 2 2 2}}]}]
girl2 dog2 2

Joins 预加载

Join Preload 会使用 inner join 加载关联数据

注意 Join Preload 适用于一对一的关系,例如: has one, belongs to

func main() {
  db, _ := gorm.Open(mysql.New(mysql.Config{DSN: "root:123456@tcp(127.0.0.1:3306)/gormDB?charset=utf8mb4&parseTime=True&loc=Local"}), &gorm.Config{})
  db.AutoMigrate(&GirlGOD{}, &Dog{}, &Info{})
  var girls []GirlGOD
  db.Debug().Preload("Dogs", func(db *gorm.DB) *gorm.DB {
    return db.Joins("Info").Where("money>1")
  }).Find(&girls)
  fmt.Println(girls)
}
SELECT `dogs`.`id`,
       `dogs`.`created_at`,
       `dogs`.`updated_at`,
       `dogs`.`deleted_at`,
       `dogs`.`name`,
       `dogs`.`girl_god_id`,
       `Info`.`id`         AS `Info__id`,
       `Info`.`created_at` AS `Info__created_at`,
       `Info`.`updated_at` AS `Info__updated_at`,
       `Info`.`deleted_at` AS `Info__deleted_at`,
       `Info`.`age`        AS `Info__age`,
       `Info`.`money`      AS `Info__money`,
       `Info`.`dog_id`     AS `Info__dog_id`
FROM `dogs`
         LEFT JOIN `infos` `Info` ON `dogs`.`id` = `Info`.`dog_id` AND `Info`.`deleted_at` IS NULL
WHERE money > 1
  AND `dogs`.`girl_god_id` IN (1, 2)
  AND `dogs`.`deleted_at` IS NULL


相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
4月前
|
SQL XML Java
mybatis复习04高级查询 一对多,多对一的映射处理,collection和association标签的使用
文章介绍了MyBatis中高级查询的一对多和多对一映射处理,包括创建数据库表、抽象对应的实体类、使用resultMap中的association和collection标签进行映射处理,以及如何实现级联查询和分步查询。此外,还补充了延迟加载的设置和用法。
mybatis复习04高级查询 一对多,多对一的映射处理,collection和association标签的使用
|
8月前
gorm 多对多关系 以及 关联的操作
gorm 多对多关系 以及 关联的操作
130 0
|
8月前
|
数据库 索引
gorm 多态以及关联标签
gorm 多态以及关联标签
73 0
|
Java 数据库连接 mybatis
【MyBatis】学习笔记12:通过级联属性赋值解决多对一的映射关系
【MyBatis】学习笔记12:通过级联属性赋值解决多对一的映射关系
175 0
【MyBatis】学习笔记12:通过级联属性赋值解决多对一的映射关系
|
存储 关系型数据库 数据库
[译] 如何用 Room 处理一对一,一对多,多对多关系?
[译] 如何用 Room 处理一对一,一对多,多对多关系?
[译] 如何用 Room 处理一对一,一对多,多对多关系?
|
Java 数据库连接 数据格式
hibernate笔记--单向一对多映射方法
  上一篇讲的是单向多对一的表关系,与单向一对多的关系正好相反,如下图所示关系: ,可以看出年级表和学生表是一对多的关系,一条年级信息对应多条学生信息,在hibernate中成为单向的一对多的映射关系,应该这些操作:   新建Student实体类: public class Stude...
767 0
|
Java 数据库连接 数据格式
hibernate笔记--双向一对多映射方法
  前两节写了两个例子,分别是单向多对一的映射和单向一对多的映射,这一节继续以这个例子讲一下双向一对多的映射方法,如下图所示:   很多时候,我们既想从一对端获取多对端的信息,又想从多对端获取一对端的数据,这就是需要双向一对多的映射关系,这也是最常见的表与表的映射关系,在hibernate中应当这...
1013 0
|
XML Java 数据库连接
hibernate笔记--继承映射关系的三种实现方式
单表继承映射(一张表):   假设我们现在有三个类,关系如下:             Person类有两个子类Student和Teacher,并且子类都具有自己独有的属性.这种实体关系在hibernate中可以使用单表的继承映射来建表,最后生成的表是这样的:   可以看到我们只需要建立...
1077 0
|
Java 数据库连接 数据库
hibernate笔记--单向多对一映射方法
  假设我们要建两张表,学生信息表(student)和年级信息表(grade),关系是这样的:   我们可以看出学生表和=年级表是多对一的关系,多个学生会隶属于一个班级,这种关系在hibernate中成为单边的多对一的关系,需要这样配置: 新建实体类Grade: public clas...
924 0

热门文章

最新文章