gorm 一对一关系 以及 关联的操作

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

Belongs To

理解:A属于B------>A依赖B,A要有外键映射到B

belongs to 会与另一个模型建立了一对一的连接。 这种模型的每一个实例都“属于”另一个模型的一个实例。(员工 属于 公司)

例如,您的应用包含 user 和 company,并且每个 user 能且只能被分配给一个 company。下面的类型就表示这种关系。 注意,在 User 对象中,有一个和 Company 一样的 CompanyID。 默认情况下, CompanyID 被隐含地用来在 User 和 Company 之间创建一个外键关系, 因此必须包含在 User 结构体中才能填充 Company 内部结构体。

关系主题是A,是员工User

type User struct {
  gorm.Model
  Name      string
  CompanyID int
  Company   Company
}
type Company struct {
  gorm.Model
  Name string
}

这里自动迁移AutoMigrate的时候,只迁移User表,也会将Company表创建出来,因为user是依赖company的

这里创建wxf这个用户,会自动在公司表中将公司company1也创建出来

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(&User{})
  user:=User{
    Name:      "wxf",
    Company:   Company{
      Name:  "company1",
    },
  }
  db.Debug().Create(&user)
}
2022/05/15 20:52:31 C:/Users/68725/Desktop/leetcode/main.go:29
[39.169ms] [rows:1] INSERT INTO `companies` (`created_at`,`updated_at`,`deleted_at`,`name`) VALUES ('2022-05-15 20:52:31.668','2022-05-15 20:52:31.668',NULL,'company1') ON DUPLICATE KEY UPDATE `id`=`id`
2022/05/15 20:52:31 C:/Users/68725/Desktop/leetcode/main.go:29
[42.952ms] [rows:1] INSERT INTO `users` (`created_at`,`updated_at`,`deleted_at`,`name`,`company_id`) VALUES ('2022-05-15 20:52:31.707','2022-05-15 20:52:31.707',NULL,'wxf',1)

Has One

理解:A有一个B------>A可有可无B,但一个存在B,必定B是属于A的,B依赖A,B要存在一个外键映射到A

has one 与另一个模型建立一对一的关联,但它和一对一关系有些许不同。 这种关联表明一个模型的每个实例都包含或拥有另一个模型的一个实例。

例如,您的应用包含 user 和 credit card 模型,且每个 user 只能有一张 credit card。

关系主体是A,是User

// User 有一张 CreditCard,UserID 是外键
type User struct {
  gorm.Model
  CreditCard CreditCard
}
type CreditCard struct {
  gorm.Model
  Number string
  UserID uint
}

这里自动迁移AutoMigrate的时候,只迁移User表,不会自动创建CreditCard 表,因为User表不依赖于CreditCard 表

创建user的时候,会自动将creditcard也创建出来

// User 有一张 CreditCard,UserID 是外键
type User struct {
  gorm.Model
  CreditCard CreditCard
}
type CreditCard struct {
  gorm.Model
  Number string
  UserID 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(&User{}, &CreditCard{})
  user := User{
    CreditCard: CreditCard{
      Number: "111",
    },
  }
  db.Debug().Create(&user)
}
2022/05/15 21:12:34 C:/Users/68725/Desktop/leetcode/main.go:29
[0.510ms] [rows:1] INSERT INTO `credit_cards` (`created_at`,`updated_at`,`deleted_at`,`number`,`user_id`) VALUES ('2022-05-15 21:12:34.492','2022-05-15 21:12:34.492',NULL,'111',1) ON DUPLICATE KEY UPDATE `user_id`=VALUES(`user_id`)
2022/05/15 21:12:34 C:/Users/68725/Desktop/leetcode/main.go:29
[48.298ms] [rows:1] INSERT INTO `users` (`created_at`,`updated_at`,`deleted_at`) VALUES ('2022-05-15 21:12:34.445','2022-05-15 21:12:34.445',NULL)

预加载

预加载:可以知道身上挂着关系的具体结构的信息

在Has One模式中,我们想去查询user的信息,发现user的信息是有了,但是没有creditcard 的信息

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(&User{}, &CreditCard{})
  var user User
  db.Debug().First(&user)
  fmt.Printf("%+v\n", user)
}
2022/05/15 21:19:13 C:/Users/68725/Desktop/leetcode/main.go:26
[42.711ms] [rows:1] SELECT * FROM `users` WHERE `users`.`deleted_at` IS NULL ORDER BY `users`.`id` LIMIT 1
{Model:{ID:1 CreatedAt:2022-05-15 21:12:34.445 +0800 CST UpdatedAt:2022-05-15 21:12:34.445 +0800 CST DeletedAt:{Time:0001-01-01 00:00:00 +0000 UTC Valid:false}} CreditCard:{Model:{ID:0 CreatedAt:0001-01-01 00:00:00 +0000 UTC UpdatedAt:0001-01-01 00:00:00 +0000 UTC DeletedAt:{Time:0001-01-01 00:00:00 +0000 UTC Valid:false}} Number: UserID:0}}

所以我们需要使用到预加载,只要我们的结构包含了另一个结构,不论是has one还是belongs to,还是many2many等关系,我们都可以用预加载把关系给带出来。

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(&User{}, &CreditCard{})
  var user User
  db.Debug().Preload("CreditCard").First(&user)
  fmt.Printf("%+v\n", user)
}
2022/05/15 21:20:49 C:/Users/68725/Desktop/leetcode/main.go:26
[0.705ms] [rows:1] SELECT * FROM `credit_cards` WHERE `credit_cards`.`user_id` = 1 AND `credit_cards`.`deleted_at` IS NULL
2022/05/15 21:20:49 C:/Users/68725/Desktop/leetcode/main.go:26
[47.026ms] [rows:1] SELECT * FROM `users` WHERE `users`.`deleted_at` IS NULL ORDER BY `users`.`id` LIMIT 1
{Model:{ID:1 CreatedAt:2022-05-15 21:12:34.445 +0800 CST UpdatedAt:2022-05-15 21:12:34.445 +0800 CST DeletedAt:{Time:0001-01-01 00:00:00 +0000 UTC Valid:false}} CreditCard:{Model:{ID:1 CreatedAt:2022-05-15 21:12:34.492 +0800 CST UpdatedAt:2022-05-15 21:12:34.492 +0800 CST DeletedAt:{Time:0001-01-01 00:00:00 +0000 UTC Valid:false}} Number:111 UserID:1}}

关系操作

  • 需要先确定关联模型Model,源模型的主键不能为空
  • Find 查找
  • Append 添加关系
  • Delete 删除关系
  • Replace 替换关系
  • Clear 清楚所有关系
  • Count 关联计数

以 has one 为例

确定关联模型

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(&User{}, &CreditCard{})
  // 开始关联模式
  var user User
  // `user` 是源模型,它的主键不能为空
  // 关系的字段名是 `CreditCard`
  // 如果匹配了上面两个要求,会开始关联模式,否则会返回错误
  user.Model.ID=1
  db.Model(&user).Association("CreditCard")
  fmt.Println(db.Model(&user).Association("CreditCard").Error)
}

查找关联

查找所有匹配的关联记录

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(&User{}, &CreditCard{})
  var user User
  user.Model.ID = 1
  var cc CreditCard
  db.Model(&user).Association("CreditCard").Find(&cc)
  fmt.Println(cc)
}

添加关联

为 many to many、has many 添加新的关联;为 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(&User{}, &CreditCard{})
  var user User
  user.Model.ID = 1
  cc2 := CreditCard{
    Number: "222",
  }
  db.Debug().Model(&user).Association("CreditCard").Append(&cc2)
}
2022/05/15 21:41:03 C:/Users/68725/Desktop/leetcode/main.go:32
[0.841ms] [rows:1] INSERT INTO `credit_cards` (`created_at`,`updated_at`,`deleted_at`,`number`,`user_id`) VALUES ('2022-05-15 21:41:03.851','2022-05-15 21:41:03.851',NULL,'222',1) ON DUPLICATE KEY UPDATE `user_id`=VALUES(`user_id`)
2022/05/15 21:41:03 C:/Users/68725/Desktop/leetcode/main.go:32
[54.519ms] [rows:1] UPDATE `users` SET `updated_at`='2022-05-15 21:41:03.8' WHERE `users`.`deleted_at` IS NULL AND `id` = 1
2022/05/15 21:41:03 C:/Users/68725/Desktop/leetcode/main.go:32
[1.544ms] [rows:1] UPDATE `credit_cards` SET `user_id`=NULL WHERE `credit_cards`.`id` <> 2 AND `credit_cards`.`user_id` = 1 AND `credit_cards`.`deleted_at` IS NULL

替换关联

用一个新的关联替换当前的关联

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(&User{}, &CreditCard{})
  var user User
  user.Model.ID = 1
  cc2 := CreditCard{
    Number: "222",
  }
  cc3 := CreditCard{
    Number: "333",
  }
  db.Debug().Model(&user).Association("CreditCard").Replace(&cc3)
}
2022/05/15 21:43:00 C:/Users/68725/Desktop/leetcode/main.go:33
[0.528ms] [rows:1] INSERT INTO `credit_cards` (`created_at`,`updated_at`,`deleted_at`,`number`,`user_id`) VALUES ('2022-05-15 21:43:00.089','2022-05-15 21:43:00.089',NULL,'333',1) ON DUPLICATE KEY UPDATE `user_id`=VALUES(`user_id`)
2022/05/15 21:43:00 C:/Users/68725/Desktop/leetcode/main.go:33
[56.931ms] [rows:1] UPDATE `users` SET `updated_at`='2022-05-15 21:43:00.035' WHERE `users`.`deleted_at` IS NULL AND `id` = 1
2022/05/15 21:43:00 C:/Users/68725/Desktop/leetcode/main.go:33
[2.768ms] [rows:1] UPDATE `credit_cards` SET `user_id`=NULL WHERE `credit_cards`.`id` <> 3 AND `credit_cards`.`user_id` = 1 AND `credit_cards`.`deleted_at` IS NULL

删除/清空 关联

删除关联:如果存在,则删除源模型与参数之间的关系,只会删除引用,不会从数据库中删除这些对象。

清空关联:删除源模型与关联之间的所有引用,但不会删除这些关联

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(&User{}, &CreditCard{})
  var user User
  user.Model.ID = 1
  cc3 := CreditCard{
    Number: "333",
  }
  db.Debug().Model(&user).Association("CreditCard").Delete(&cc3)
  db.Debug().Model(&user).Association("CreditCard").Clear()
}


相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
7月前
gorm 一对多关系 以及预加载的用法
gorm 一对多关系 以及预加载的用法
121 0
|
SQL Java 数据库连接
认识Mybatis的关联关系映射,灵活关联表对象之间的关系
认识Mybatis的关联关系映射,灵活关联表对象之间的关系
203 0
|
7月前
gorm 多对多关系 以及 关联的操作
gorm 多对多关系 以及 关联的操作
123 0
|
6月前
|
数据库 Python
使用自关联方法处理多表关系
使用自关联方法处理多表关系
|
7月前
|
数据库 索引
gorm 多态以及关联标签
gorm 多态以及关联标签
66 0
关联更新封装(三)
关联更新封装(三)
58 2
关联更新封装(二)
关联更新封装(二)
61 2
|
关系型数据库 MySQL 数据库
SQLAlchemy关联表一对多关系的详解
SQLAlchemy关联表一对多关系的详解
|
数据库 数据安全/隐私保护 索引
Gorm学习(五)进阶:多态关联、关联标签以及事务
出现需要外键引用多个表的情况,不可能删除原来表结构,重新添加一个外键ID再建表,所以我们可以建立一个交叉表。让Addres不再依赖于User表或者Order表。
826 1
Gorm学习(五)进阶:多态关联、关联标签以及事务