二丫讲梵 二丫讲梵
首页
  • 最佳实践
  • 迎刃而解
  • Nginx
  • Php
  • Zabbix
  • AWS
  • Prometheus
  • Grafana
  • CentOS
  • Systemd
  • Docker
  • Rancher
  • Ansible
  • Ldap
  • Gitlab
  • GitHub
  • Etcd
  • Consul
  • RabbitMQ
  • Kafka
  • MySql
  • MongoDB
  • OpenVPN
  • KVM
  • VMware
  • Other
  • ELK
  • K8S
  • LLM
  • Nexus
  • Jenkins
  • 随写编年
  • 家人物语
  • 追忆青春
  • 父亲的朋友圈
  • 电影音乐
  • 效率工具
  • 博客相关
  • Shell
  • 前端实践
  • Vue学习笔记
  • Golang学习笔记
  • Golang编程技巧
  • 学习周刊
  • Obsidian插件周刊
关于
友链
  • 本站索引

    • 分类
    • 标签
    • 归档
  • 本站页面

    • 导航
    • 打赏
  • 我的工具

    • 备忘录清单 (opens new window)
    • json2go (opens new window)
    • gopher (opens new window)
    • 微信MD编辑 (opens new window)
    • 国内镜像 (opens new window)
    • 出口IP查询 (opens new window)
    • 代码高亮工具 (opens new window)
  • 外站页面

    • 开往 (opens new window)
    • ldapdoc (opens new window)
    • HowToStartOpenSource (opens new window)
    • vdoing-template (opens new window)
GitHub (opens new window)

二丫讲梵

行者常至,为者常成
首页
  • 最佳实践
  • 迎刃而解
  • Nginx
  • Php
  • Zabbix
  • AWS
  • Prometheus
  • Grafana
  • CentOS
  • Systemd
  • Docker
  • Rancher
  • Ansible
  • Ldap
  • Gitlab
  • GitHub
  • Etcd
  • Consul
  • RabbitMQ
  • Kafka
  • MySql
  • MongoDB
  • OpenVPN
  • KVM
  • VMware
  • Other
  • ELK
  • K8S
  • LLM
  • Nexus
  • Jenkins
  • 随写编年
  • 家人物语
  • 追忆青春
  • 父亲的朋友圈
  • 电影音乐
  • 效率工具
  • 博客相关
  • Shell
  • 前端实践
  • Vue学习笔记
  • Golang学习笔记
  • Golang编程技巧
  • 学习周刊
  • Obsidian插件周刊
关于
友链
  • 本站索引

    • 分类
    • 标签
    • 归档
  • 本站页面

    • 导航
    • 打赏
  • 我的工具

    • 备忘录清单 (opens new window)
    • json2go (opens new window)
    • gopher (opens new window)
    • 微信MD编辑 (opens new window)
    • 国内镜像 (opens new window)
    • 出口IP查询 (opens new window)
    • 代码高亮工具 (opens new window)
  • 外站页面

    • 开往 (opens new window)
    • ldapdoc (opens new window)
    • HowToStartOpenSource (opens new window)
    • vdoing-template (opens new window)
GitHub (opens new window)
  • Shell编程

  • Go编程笔记

    • 开发技巧

    • 库包研究

      • 使用gorm进行联合查询的整理总结
      • 一个ftp客户端的封装
      • 使用go-bindata将文件编译进二进制
      • go-gitlab包源码探寻与心得
      • 利用cobra库快速开发类似kubectl一样的命令行工具
      • 使用MongoDB官方go库操作MongoDB
      • 再探-利用gorm自身提供的方法实现MySQL中数据关联的能力
      • 使用retry-go给项目添加重试机制
      • go-cache包的使用简析
      • 利用gorm自身提供的方法实现存在更新不存在则创建的能力
      • 近期关于cobra库的一些实践心得总结
    • 个人项目

  • 前端编程笔记

  • Go学习笔记

  • Vue-21年学习笔记

  • Vue-22年重学笔记

  • 编程世界
  • Go编程笔记
  • 库包研究
二丫讲梵
2022-04-10

再探-利用gorm自身提供的方法实现MySQL中数据关联的能力

文章发布较早,内容可能过时,阅读注意甄别。

之前在使用 gorm 对接 MySQL 的时候,关联的方案使用的是自己维护的外键方式,最近重新接触 gorm,发现其内部支持关联的更好实现,这里整理记录一下。

代码内容如下:

package main

import (
	"fmt"

	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

var db *gorm.DB

// User 用户模型
type User struct {
	gorm.Model
	UserName string `gorm:"type:varchar(128)" json:"userName"` // 用户名
	NickName string `gorm:"type:varchar(128)" json:"nickName"` // 昵称
}

// Group 分组
type Group struct {
	gorm.Model
	GroupName string  `json:"groupName"  gorm:"type:varchar(128);"` //部门名称
	Users     []*User `gorm:"many2many:group_users" json:"users"`
}

// InitDB 初始化DB
func InitDB() {

	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=%s&collation=%s&%s",
		"root",
		"123465",
		"localhost",
		3306,
		"test-gorm",
		"utf8mb4",
		"utf8mb4_general_ci",
		"parseTime=true",
	)
	var err error
	db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
		// 禁用外键(指定外键时不会在mysql创建真实的外键约束)
		DisableForeignKeyConstraintWhenMigrating: true,
		//// 指定表前缀
		//NamingStrategy: schema.NamingStrategy{
		//	TablePrefix: config.Conf.Mysql.TablePrefix + "_",
		//},
	})
	if err != nil {
		panic(fmt.Errorf("初始化mysql数据库异常: %v", err))
	}

	// 2, 把模型与数据库中的表对应起来
	dbAutoMigrate()
}

// 自动迁移表结构
func dbAutoMigrate() {
	db.AutoMigrate(
		&User{},
		&Group{},
	)
}

func main() {
	// 1,初始化
	InitDB()

	// 2,创建测试数据
	CreateUser()
	CreateGroup()

	// 新增关联
	AddRelation()
	// 查询关联
	SelectRelation()
	// 替换关联
	ReplaceRelation()
	// 清空关联
	ClearRelation()
	// 删除关联
	RemoveRelation()
	// 计数关联
	CountRelation()

}

func SelectRelation() {
	var data Group
	id := 1
	err := db.Debug().Where("id = ?", id).Preload("Users").Find(&data).Error
	if err != nil {
		fmt.Printf("err: %v\n", err)
	}
	for _, users := range data.Users {
		fmt.Println(users)
	}
}

func AddRelation() {
	var group Group
	var users []User
	ids := []int{1, 2}
	err := db.Where("id IN (?)", ids).Find(&users).Error // 查询ID为1和2的用户
	if err != nil {
		fmt.Printf("err: %v\n", err)
	}
	db.First(&group, 1)

	// 将刚刚查询到的用户添加到分组中
	db.Model(&group).Association("Users").Append(users)
}

func ReplaceRelation() {
	var group Group
	var users []User
	// 全量替换关联
	ids1 := []int{3, 4}
	err1 := db.Where("id IN (?)", ids1).Find(&users).Error // 查询ID为1和2的用户
	if err1 != nil {
		fmt.Printf("err: %v\n", err1)
	}
	db.Model(&group).Association("Users").Replace(users) // 全量替换关联
}

func ClearRelation() {
	var group Group
	db.First(&group, 1)
	db.Model(&group).Association("Users").Clear()
}

func RemoveRelation() {
	var group Group
	var users []User
	ids1 := []int{1, 2}
	err1 := public.DB.Where("id IN (?)", ids1).Find(&users).Error // 查询ID为1和2的用户
	if err1 != nil {
		fmt.Printf("err: %v\n", err1)
	}

	// 先查询到将要解除关联的group
	err := public.DB.First(&group, 1).Error
	if err != nil {
		fmt.Printf("get group data failed:%v\n", err)
	}
	err = public.DB.Model(&group).Association("Users").Delete(users)
	if err != nil {
		fmt.Printf("delete relation failed:%v\n", err)
	}
}

func CountRelation() {
	// 关联计数
	var group Group
	db.First(&group, 1)
	i := db.Model(&group).Association("Users").Count()
	fmt.Printf("i: %v\n", i)
}

// CreateUser 创建用户
func CreateUser() {
	User1 := &User{UserName: "eryajf1", NickName: "二丫讲梵1"}
	User2 := &User{UserName: "eryajf2", NickName: "二丫讲梵2"}
	User3 := &User{UserName: "eryajf3", NickName: "二丫讲梵3"}
	User4 := &User{UserName: "eryajf4", NickName: "二丫讲梵4"}
	User5 := &User{UserName: "eryajf5", NickName: "二丫讲梵5"}
	db.Debug().Model(&User{}).Create(&User1)
	db.Debug().Model(&User{}).Create(&User2)
	db.Debug().Model(&User{}).Create(&User3)
	db.Debug().Model(&User{}).Create(&User4)
	db.Debug().Model(&User{}).Create(&User5)
}

func CreateGroup() {
	g1 := &Group{GroupName: "ops"}
	g2 := &Group{GroupName: "test"}
	db.Debug().Model(&Group{}).Create(&g1)
	db.Debug().Model(&Group{}).Create(&g2)
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
  • 参考:
    • Many To Many (opens new window)
    • ORM 框架-实体关联 (opens new window)
微信 支付宝
上次更新: 2024/06/13, 22:13:45
使用MongoDB官方go库操作MongoDB
使用retry-go给项目添加重试机制

← 使用MongoDB官方go库操作MongoDB 使用retry-go给项目添加重试机制→

最近更新
01
学习周刊-总第213期-2025年第22周
05-29
02
学习周刊-总第212期-2025年第21周
05-22
03
从赵心童世锦赛夺冠聊聊我的斯诺克情缘
05-16
更多文章>
Theme by Vdoing | Copyright © 2017-2025 | 点击查看十年之约 | 浙ICP备18057030号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式