一.GORM概述
1.学习方法
3w1h指What、Why、Where、How。
学技术也有方法可言,比如学习一个新的技术gorm:
- 新手期:
先到百度搜索几篇基本的用法案例,粘贴过来测试一下,测试通了说明你对grom有一个基础的了解。
- 筑基期:
到官方系统的整理,最好整理成博客,以便于以后用的时候方便查询,但这只是学会了基础语法。
- 结丹期:
如何将学到的东西融入到项目中,最好给自己找几个需求,然后练习实现,从而不断让自己的技术沉淀。
如果没有案例的话,可以在GitHub或者gitee上找一些开源项目模仿跑通。
如果你真的能做到这个阶段,保守估计,想必你的薪资应该不会低于: 35K+
- 化神期:
读源码和实现原理,参加过大厂面试的小伙伴应该都知道,他们很喜欢为什么问底层原理,其实了解底层原理有助于咱们做故障排查。
比如公司要实现一个CMDB系统,你如果了解类似相关产品的实现方案的底层原理,想必你动手写应该不会毫无头绪。
2.orm是一种术语而不是软件
- orm英文全称object relational mapping,就是 对象映射关系 程序
- 简单来说类似python这种面向对象的程序来说一切皆对象,但是我们使用的数据库却都是关系型的
- 为了保证一致的使用习惯,通过orm将编程语言的对象模型和数据库的关系模型建立映射关系
- 这样我们直接使用编程语言的对象模型进行操作数据库就可以了,而不用直接使用sql语言
3.什么是grom
gorm是一个使用Go语言编写的ORM框架。它文档齐全,对开发者友好,支持主流数据库。
gorm官方中文文档:https://gorm.io/zh_CN/docs/
二.GORM基本使用
1.安装gorm
go get -u gorm.io/gorm
go get -u gorm.io/driver/sqlite
go get -u gorm.io/driver/mysql
2.创建数据库
1.创建数据库和表信息
CREATE DATABASE yinzhengjie CHARSET utf8mb4;
USE yinzhengjie;
CREATE TABLE users(
id BIGINT(20) PRIMARY KEY AUTO_INCREMENT COMMENT '用户ID',
username VARCHAR(255) NOT NULL COMMENT '用户名',
password VARCHAR(255) NOT NULL COMMENT '密码',
status ENUM('active', 'inactive', 'deleted') NOT NULL DEFAULT 'active' COMMENT '用户状态'
);
2.查看表结构信息
mysql> DESC users;
+----------+-------------------------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------------------------------+------+-----+---------+----------------+
| id | bigint | NO | PRI | NULL | auto_increment |
| username | varchar(255) | NO | | NULL | |
| password | varchar(255) | NO | | NULL | |
| status | enum('active','inactive','deleted') | NO | | active | |
+----------+-------------------------------------+------+-----+---------+----------------+
4 rows in set (0.00 sec)
mysql>
3.配置远程用户授权访问
CREATE USER IF NOT EXISTS admin IDENTIFIED WITH mysql_native_password BY 'yinzhengjie';
GRANT ALL ON yinzhengjie.* TO admin;
4.查看权限验证
mysql> SHOW GRANTS FOR 'admin';
+--------------------------------------------------------+
| Grants for admin@% |
+--------------------------------------------------------+
| GRANT USAGE ON *.* TO `admin`@`%` |
| GRANT ALL PRIVILEGES ON `yinzhengjie`.* TO `admin`@`%` |
+--------------------------------------------------------+
2 rows in set (0.00 sec)
mysql>
5.访问测试
[root@yinzhengjie ~]# mysql -uadmin -pyinzhengjie -h 10.0.0.20 -e 'SHOW DATABASES;'
mysql: [Warning] Using a password on the command line interface can be insecure.
+--------------------+
| Database |
+--------------------+
| information_schema |
| yinzhengjie |
+--------------------+
[root@yinzhengjie ~]#
3.连接数据库创建表
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
type UserInfo struct {
/**
json:"id"
在json格式解析时字段名称为id。
grom:"primary_key"
对于grom框架而言,声明该字段为主键。
*/
Id int64 `json:"id" grom:"primary_key"`
Username string
Password string
}
func main() {
// 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情
dsn := "admin:yinzhengjie@tcp(10.0.0.20:3306)/yinzhengjie?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
fmt.Printf("连接数据库出错: %v\n", err)
panic(err) // 如果连接出错,就直接抛出异常!
}
fmt.Printf("数据库连接成功: %v\n", db)
/**
使用AutoMigrate自动创建表结构.
参考连接:
https://gorm.io/zh_CN/docs/migration.html
这个语句慎用,因为其创建的表的数据类型可能比我们预期要给的大:
mysql> desc user_infos;
+----------+----------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+----------+------+-----+---------+----------------+
| id | bigint | NO | PRI | NULL | auto_increment |
| username | longtext | YES | | NULL | |
| password | longtext | YES | | NULL | |
+----------+----------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
mysql>
*/
err = db.AutoMigrate(UserInfo{})
if err != nil {
panic(fmt.Sprintf("表创建失败,%v\n", err))
}
fmt.Println("数据表创建成功!")
}
4.单表的增删改查
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
type UserInfo struct {
Id int64 `json:"id" grom:"primary_key"`
Username string
Password string
}
func main() {
dsn := "admin:yinzhengjie@tcp(10.0.0.20:3306)/yinzhengjie?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
fmt.Printf("连接数据库出错: %v\n", err)
panic(err) // 如果连接出错,就直接抛出异常!
}
err = db.AutoMigrate(UserInfo{})
// 1.向数据库添加数据,注意多次执行会创建多个用户哟,而且会自动基于ID自增,小心造成数据的重复创建哟!
db.Create(&UserInfo{
Username: "JasonYin",
Password: "yinzhengjie",
})
db.Create(&UserInfo{
Username: "root",
Password: "yinzhengjie",
})
db.Create(&UserInfo{
Username: "root",
Password: "123",
})
// 2.修改表中的某一个字段
db.Model(UserInfo{
Id: 1,
}).Update("password", "123")
// 4. 过滤查询数据单条数据
u1 := UserInfo{Username: "root"}
db.Where("username= ?", u1.Username).First(&u1)
fmt.Printf("u1 ---> %#v\n", u1)
// 5. 过滤查询数据多条数据
u2 := UserInfo{Username: "root"}
u2_all_user := []UserInfo{}
db.Where("username= ?", u2.Username).Find(&u2_all_user)
fmt.Printf("u2---> %#v\n", u2_all_user)
// 6.查看所有数据
users := []UserInfo{} // 定义一个UserInfo结构体切片来接收数据
db.Find(&users)
fmt.Printf("all ---> %#v\n", users)
// 7.删除数据
// 7.1 基于主键id删除,比如删除id为1的数据
db.Delete(&UserInfo{Id: 1})
// 7.2 基于条件删除,比如基于username为root的数据进行删除
db.Where("username =?", "root").Delete(&UserInfo{})
}
5.数据库的模型定义
package main
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
"time"
)
type User struct {
/**
声明 model时,tag是可选的,GORM支持以下tag。
column:
指定db列名
type:
列数据类型,推荐使用兼容性好的通用类型,
例如:所有数据库都支持 bool、int、uint、float、string、time、bytes 并且可以和其他标签一起使用,
例如:not null、size, autoIncrement… 像 varbinary(8) 这样指定数据库数据类型也是支持的。
在使用指定数据库数据类型时,它需要是完整的数据库数据类型,如:MEDIUMINT UNSIGNED not NULL AUTO_INCREMENT
serializer:
指定将数据序列化或反序列化到数据库中的序列化器, 例如: serializer:json/gob/unixtime
size:
定义列数据类型的大小或长度,例如 size: 256
primaryKey:
将列定义为主键
unique:
将列定义为唯一键
default:
定义列的默认值
precision:
指定列的精度
scale:
指定列大小
not null:
指定列为NOT NULL
autoIncrement:
指定列为自动增长
autoIncrementIncrement:
自动步长,控制连续记录之间的间隔
embedded:
嵌套字段
embeddedPrefix:
嵌入字段的列名前缀
autoCreateTime:
创建时追踪当前时间,对于 int 字段,它会追踪时间戳秒数,您可以使用 nano/milli 来追踪纳秒、毫秒时间戳,例如:autoCreateTime:nano
autoUpdateTime:
创建/更新时追踪当前时间,对于 int 字段,它会追踪时间戳秒数,您可以使用 nano/milli 来追踪纳秒、毫秒时间戳,例如:autoUpdateTime:milli
index:
根据参数创建索引,多个字段使用相同的名称则创建复合索引,查看 索引 获取详情
uniqueIndex:
与 index 相同,但创建的是唯一索引
check:
创建检查约束,例如 check:age > 13,查看 约束 获取详情
<-:
设置字段写入的权限, <-:create 只创建、<-:update 只更新、<-:false 无写入权限、<- 创建和更新权限
->:
设置字段读的权限,->:false 无读权限
-:
忽略该字段,- 表示无读写,-:migration 表示无迁移权限,-:all 表示无读写迁移权限
comment:
迁移时为字段添加注释
tag名大小写不敏感,但建议使用camelCase风格。
更多资料请参考官网:
https://gorm.io/zh_CN/docs/models.html
*/
Id int64 `gorm:"primary_key" json:"id"`
Name string // 默认字符串对应的是数据库的longtext文本类型
CreatedAt *time.Time `json:"createdAt" gorm:"column:create_at"`
Email string `gorm:"type:varchar(255);unique_index"` // 使用type字段定义类型,并设置为唯一索引
Role string `gorm:"size:255"` // 设置字段的大小为255个字节
MemberNumber *string `gorm:"unique;not null"` // 设置memberNumber 字段唯一且不为空
Num int `gorm:"AUTO_INCREMENT"` // 设置 Num字段自增
Address string `gorm:"index:addr"` // 给Address 创建一个名字是 `addr`的索引
IgnoreMe int `gorm:"-"` // 忽略这个字段
}
func main() {
dsn := "admin:yinzhengjie@tcp(10.0.0.20:3306)/yinzhengjie?charset=utf8mb4&parseTime=True&loc=Local"
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
// 创建表
err := db.AutoMigrate(User{})
if err != nil {
panic(err)
}
}
三.一对多关联查询
1.has many 一对多概述
has many关联就是创建一个和另一个模型的一对多关系。
例如: 每一个用户都有多张信用卡,这样就是生活中一个简单的一对多关系。
定义关系:
type User struct {
// gorm.Model是gorm内置的模块,已经定义好了相关的结构体咱们可以直接引用
gorm.Model
CreditCard []CreditCard
}
type CreditCard struct {
gorm.Model
Number string
// 默认会在CreditCard表中生成UserID字段作为User表关联的外键ID
UserID uint
}
推荐阅读:
https://gorm.io/zh_CN/docs/has_many.html
2.外键
- 为了定义一对多关系, 外键是必须存在的,默认外键的名字是 所有者类型的名字加上它的主键
- 就像上面的例子,为了定义一个属于User的模型,外键就应该为UserID 。
- 使用其他的字段名作为外键, 你可以通过"foreignkey"来定制它,
举个例子:
type User struct {
gorm.Model
CreditCard []CreditCard `gorm:"foreignkey:UserRef"`
}
type CreditCard struct {
gorm.Model
Number string
UserRef uint
}
3.外键关联
- GORM通常使用拥有者的主键作为外键的值。 对于上面的例子,它是User的ID字段。
- 为user添加creditcard 时,GORM 会将user的ID字段保存到creditcard的UserID 字段。
- 同样的,您也可以使用标签 references 来更改它。
举个例子:
type User struct {
gorm.Model
MemberNumber string
CreditCards []CreditCard `gorm:"foreignKey:UserNumber;references:MemberNumber"`
}
type CreditCard struct {
gorm.Model
Number string
UserNumber string
}
4.外键约束
你可以通过为标签 constraint 配置 OnUpdate、OnDelete 实现外键约束,在使用 GORM 进行迁移时它会被创建.
举个例子:
type User struct {
gorm.Model
CreditCards []CreditCard `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
}
type CreditCard struct {
gorm.Model
Number string
UserID uint
}
5.一对多案例
package main
import (
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
// 2.建立一对多关系
type User struct {
gorm.Model
Username string `json:"username gorm:"column:username"`
// 添加外键关联,只要该字段是一个CreditCard的切片,会自动和CreditCard模型建立外键关联。
CreditCards []CreditCard
}
type CreditCard struct {
gorm.Model
Number string
// 这个就是User表关联的外键,表示基于User表的ID主键(primary key)字段进行关联。这个是gorm的规定【结构体 + 主键】
UserID uint
}
func main() {
// 1.创建gorm的链接
dsn := "admin:yinzhengjie@tcp(10.0.0.20:3306)/yinzhengjie?charset=utf8mb4&parseTime=True&loc=Local"
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
fmt.Println(db)
// 3.创建表结构
//db.AutoMigrate(User{}, CreditCard{})
/**
4.创建一对多
创建后记得查看数据库信息:
mysql> SHOW TABLES;
+-----------------------+
| Tables_in_yinzhengjie |
+-----------------------+
| credit_cards |
| users |
+-----------------------+
2 rows in set (0.00 sec)
mysql>
mysql> SELECT * FROM users;
+----+-------------------------+-------------------------+------------+-----------+
| id | created_at | updated_at | deleted_at | username |
+----+-------------------------+-------------------------+------------+-----------+
| 1 | 2023-11-20 23:48:17.561 | 2023-11-20 23:48:17.561 | NULL | Jason Yin |
+----+-------------------------+-------------------------+------------+-----------+
1 row in set (0.01 sec)
mysql>
mysql> SELECT * FROM credit_cards;
+----+-------------------------+-------------------------+------------+--------+---------+
| id | created_at | updated_at | deleted_at | number | user_id |
+----+-------------------------+-------------------------+------------+--------+---------+
| 1 | 2023-11-20 23:48:17.574 | 2023-11-20 23:48:17.574 | NULL | 1001 | 1 |
| 2 | 2023-11-20 23:48:17.574 | 2023-11-20 23:48:17.574 | NULL | 1002 | 1 |
+----+-------------------------+-------------------------+------------+--------+---------+
2 rows in set (0.00 sec)
mysql>
*/
//user := User{
// Username: "Jason Yin",
// CreditCards: []CreditCard{
// {Number: "1001"},
// {Number: "1002"},
// },
//}
//
//db.Create(&user)
// 5.为已存在的用户添加信用卡
u := User{
Username: "Jason Yin",
}
db.First(&u) // 查找返回的第一条记录
// 使用Association方法基于指定"CreditCards"关联外键字段找到关联关系,并使用Append方法追加信息。
db.Model(&u).Association("CreditCards").Append([]CreditCard{
{Number: "1003"},
{Number: "1004"},
})
/**
添加成功后,再次查看表信息
mysql> SHOW TABLES;
+-----------------------+
| Tables_in_yinzhengjie |
+-----------------------+
| credit_cards |
| users |
+-----------------------+
2 rows in set (0.00 sec)
mysql>
mysql> SELECT * FROM users;
+----+-------------------------+-------------------------+------------+-----------+
| id | created_at | updated_at | deleted_at | username |
+----+-------------------------+-------------------------+------------+-----------+
| 1 | 2023-11-20 23:48:17.561 | 2023-11-21 00:00:12.988 | NULL | Jason Yin |
+----+-------------------------+-------------------------+------------+-----------+
1 row in set (0.00 sec)
mysql>
mysql> SELECT * FROM credit_cards;
+----+-------------------------+-------------------------+------------+--------+---------+
| id | created_at | updated_at | deleted_at | number | user_id |
+----+-------------------------+-------------------------+------------+--------+---------+
| 1 | 2023-11-20 23:48:17.574 | 2023-11-20 23:48:17.574 | NULL | 1001 | 1 |
| 2 | 2023-11-20 23:48:17.574 | 2023-11-20 23:48:17.574 | NULL | 1002 | 1 |
| 3 | 2023-11-21 00:00:12.991 | 2023-11-21 00:00:12.991 | NULL | 1003 | 1 |
| 4 | 2023-11-21 00:00:12.991 | 2023-11-21 00:00:12.991 | NULL | 1004 | 1 |
+----+-------------------------+-------------------------+------------+--------+---------+
4 rows in set (0.00 sec)
mysql>
*/
}
6.一对多Association关联查询【不推荐】
package main
import (
"encoding/json"
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
// 2.建立一对多关系
type User struct {
gorm.Model
Username string `json:"username gorm:"column:username"`
// 添加外键关联,只要该字段是一个CreditCard的切片,会自动和CreditCard模型建立外键关联。
CreditCards []CreditCard
}
type CreditCard struct {
gorm.Model
Number string
// 这个就是User表关联的外键,表示基于User表的ID主键(primary key)字段进行关联。
UserID uint
}
func main() {
// 1.创建gorm的链接
dsn := "admin:yinzhengjie@tcp(10.0.0.20:3306)/yinzhengjie?charset=utf8mb4&parseTime=True&loc=Local"
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
fmt.Println(db)
/**
3.查询关联表数据
使用Association方法:
1)需要把User查询好;
2)然后根据User定义中指定的AssociationForeignKey去查找CreditCard;
这种查询方式需要使用2次回表查询,效率会很低,慎用!!!
官方链接:
https://gorm.io/zh_CN/docs/associations.html#%E6%9F%A5%E6%89%BE%E5%85%B3%E8%81%94
*/
// 3.1 先查询User表数据
u := User{Username: "Jason Yin"}
db.First(&u)
//fmt.Printf("%v\n", u.Username)
// 3.2 基于AssociationForeignKey外键字段"CreditCards"进行查找
err := db.Model(&u).Association("CreditCards").Find(&u.CreditCards)
if err != nil {
panic(fmt.Sprintf("err ---> %v\n", err))
}
// 将其转换为json格式显示
bytes, _ := json.Marshal(&u)
fmt.Println(string(bytes))
}
7.一对多Preload预加载关联查询【推荐】
package main
import (
"encoding/json"
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
// 2.建立一对多关系
type User struct {
gorm.Model
Username string `json:"username gorm:"column:username"`
// 添加外键关联,只要该字段是一个CreditCard的切片,会自动和CreditCard模型建立外键关联。
CreditCards []CreditCard
}
type CreditCard struct {
gorm.Model
Number string
// 这个就是User表关联的外键,表示基于User表的ID主键(primary key)字段进行关联。
UserID uint
}
func main() {
// 1.创建gorm的链接
dsn := "admin:yinzhengjie@tcp(10.0.0.20:3306)/yinzhengjie?charset=utf8mb4&parseTime=True&loc=Local"
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
fmt.Println(db)
/**
3.使用Preload预加载方法:
在查询User时先去获取CreditCard的记录
很明显,这种效率会更高,一次性把数据查询出来,不会去回表查询两次。
推荐阅读:
https://gorm.io/zh_CN/docs/preload.html
*/
users := []User{}
db.Preload("CreditCards").Find(&users)
bytesUser, _ := json.Marshal(&users)
fmt.Println(string(bytesUser))
}
四.多对多关联查询
1.对多对关系描述
Many to Many会在两个model中添加一张连接表。
举个例子:
一个学生可以选择多个课程,一个课程又包含多个学生,这是双向对对多的关系。
推荐阅读:
https://gorm.io/zh_CN/docs/many_to_many.html
2.多对多表结构创建
package main
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
// 2.定义多对多关联表
type User struct {
gorm.Model
/**
gorm:"many2many:user_languages;"
指定了User表和Language表是多对多的关系,且"user_languages"是第三张连接表。
*/
Languages []Language `gorm:"many2many:user_languages;"`
}
type Language struct {
gorm.Model
Name string
}
func main() {
// 1.创建gorm的链接
dsn := "admin:yinzhengjie@tcp(10.0.0.20:3306)/yinzhengjie?charset=utf8mb4&parseTime=True&loc=Local"
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
/**
3.创建多对多表结构
创建成功后记得去数据库验证多对多表结构创建信息:
mysql> SHOW TABLES;
+-----------------------+
| Tables_in_yinzhengjie |
+-----------------------+
| languages |
| user_languages |
| users |
+-----------------------+
3 rows in set (0.00 sec)
mysql>
mysql> DESC users;
+------------+-----------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+-----------------+------+-----+---------+----------------+
| id | bigint unsigned | NO | PRI | NULL | auto_increment |
| created_at | datetime(3) | YES | | NULL | |
| updated_at | datetime(3) | YES | | NULL | |
| deleted_at | datetime(3) | YES | MUL | NULL | |
+------------+-----------------+------+-----+---------+----------------+
4 rows in set (0.01 sec)
mysql>
mysql> DESC languages;
+------------+-----------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+-----------------+------+-----+---------+----------------+
| id | bigint unsigned | NO | PRI | NULL | auto_increment |
| created_at | datetime(3) | YES | | NULL | |
| updated_at | datetime(3) | YES | | NULL | |
| deleted_at | datetime(3) | YES | MUL | NULL | |
| name | longtext | YES | | NULL | |
+------------+-----------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)
mysql>
mysql> DESC user_languages;
+-------------+-----------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-----------------+------+-----+---------+-------+
| user_id | bigint unsigned | NO | PRI | NULL | |
| language_id | bigint unsigned | NO | PRI | NULL | |
+-------------+-----------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
mysql>
*/
db.AutoMigrate(User{}, Language{})
}
3.多对多表结构自定义连接表
package main
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
"time"
)
// 2.定义多对多关联表
type Person struct {
ID int
Name string
// 声明对对多关系,让Person和Address表进行关联
Addresses []Address `gorm:"many2many:person_addresses;"`
}
type Address struct {
ID uint
Name string
}
// 自定义第三张表时我们除了可以关联两个表的关联字段外,还可以添加一些我们需要的字段,比如"CreatedAt",”DeletedAt“等。
type PersonAddresses struct {
// 对应Person表的主见
PersonID int `gorm:"primaryKey"`
// 对应Address表的主见
AddressID int `gorm:"primaryKey"`
CreatedAt time.Time
DeletedAt gorm.DeletedAt
}
func main() {
// 1.创建gorm的链接
dsn := "admin:yinzhengjie@tcp(10.0.0.20:3306)/yinzhengjie?charset=utf8mb4&parseTime=True&loc=Local"
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
// 3.创建第三张表
db.AutoMigrate(Person{}, Address{}, PersonAddresses{})
/**
4.添加数据
进入数据库终端查询结构如下:
mysql> SHOW TABLES;
+-----------------------+
| Tables_in_yinzhengjie |
+-----------------------+
| addresses |
| people |
| person_addresses |
+-----------------------+
3 rows in set (0.00 sec)
mysql> SELECT * FROM people;
+----+-----------+
| id | name |
+----+-----------+
| 1 | Jason Yin |
| 2 | 尹正杰 |
+----+-----------+
2 rows in set (0.00 sec)
mysql> SELECT * FROM addresses;
+----+-----------+
| id | name |
+----+-----------+
| 1 | 北京 |
| 2 | 上海 |
| 3 | 深圳 |
| 4 | 陕西 |
| 5 | 河北 |
| 6 | 山东 |
| 7 | 黑龙江 |
+----+-----------+
7 rows in set (0.00 sec)
mysql> SELECT * FROM person_addresses;
+-----------+------------+------------+------------+
| person_id | address_id | created_at | deleted_at |
+-----------+------------+------------+------------+
| 1 | 1 | NULL | NULL |
| 1 | 2 | NULL | NULL |
| 1 | 3 | NULL | NULL |
| 2 | 4 | NULL | NULL |
| 2 | 5 | NULL | NULL |
| 2 | 6 | NULL | NULL |
| 2 | 7 | NULL | NULL |
+-----------+------------+------------+------------+
7 rows in set (0.00 sec)
mysql>
*/
p1 := Person{
ID: 1,
Name: "Jason Yin",
Addresses: []Address{
{ID: 1, Name: "北京"},
{ID: 2, Name: "上海"},
{ID: 3, Name: "深圳"},
},
}
p2 := Person{
ID: 2,
Name: "尹正杰",
Addresses: []Address{
{ID: 4, Name: "陕西"},
{ID: 5, Name: "河北"},
{ID: 6, Name: "山东"},
{ID: 7, Name: "黑龙江"},
},
}
db.Create(&p1)
db.Create(&p2)
}
4.多对多Preload预加载
package main
import (
"encoding/json"
"fmt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"time"
)
// 定义多对多关系
type Person struct {
ID int
Name string
Addresses []Address `gorm:"many2many:person_addresses;"`
}
type Address struct {
ID uint
Name string
}
type PersonAddress struct {
PersonID int `gorm:"primaryKey"`
AddressID int `gorm:"primaryKey"`
CreatedAt time.Time
DeletedAt gorm.DeletedAt
}
func main() {
// 1.创建gorm的链接
dsn := "admin:yinzhengjie@tcp(10.0.0.20:3306)/yinzhengjie?charset=utf8mb4&parseTime=True&loc=Local"
db, _ := gorm.Open(mysql.Open(dsn), &gorm.Config{})
// 1.获取所有用户的地址
persons := []Person{}
db.Preload("Addresses").Find(&persons)
allData, _ := json.Marshal(&persons)
fmt.Println(string(allData))
// 2.获取 name="Jason Yin" 用户的地址
person := Person{Name: "Jason Yin"}
db.Preload("Addresses").Find(&person)
oneData, _ := json.Marshal(&person)
fmt.Println(string(oneData))
}