1. 概念
1.1 相同
都是建立模型的一对一连接,使得模型声明每个实例都「属于」另一个模型的一个实例 。
1.2 区别
假设B模型属于A模型,则B表中存在外键,它和A表中指定列关联。
- BelongsTo
B模型引用A模型,利用B模型在B表中创建数据,同时也会在A表中创建对应数据。 - Has One
A模型引用B模型,在A模型在A表中创建数据,同时也会在B表中创建对应数据。
1. BelongsTo
1.1 创建模型
- 一张users表,一张spouse表。
- 创建两个模型(结构体),使得Spouse 属于User
- 两个模型分别对应两张表:User ----> users,Spouse----> spouses
- 结构体Spouse 引用了 结构体User
则默认Spouse.UserID 对应了spouses表的外键user_id
且引用了User.ID 对应的users表的id键
type User struct {
//gorm.Model
ID int64
Name string
Age int64
}
type Spouse struct {
//gorm.Model
Name string
User User
UserID int64
Age int64
}
1.2 写入数据
创建结构体p1,将数据一次写入users、spouse两张表
p1 := &Spouse{
User: User{
Name: "LiuBei",
Age: 28,
},
Name: "SunShangXiang",
Age: 16,
}
db.Create(p1)
1.3 完整示例
- 代码
package main
import (
"fmt"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
type User struct {
//gorm.Model
ID int64
Name string
Age int64
}
type Spouse struct {
//gorm.Model
Name string
User User
UserID int64
Age int64
}
func main() {
db,_ := connect()
defer db.Close()
p1 := &Spouse{
User: User{
Name: "LiuBei",
Age: 28,
},
Name: "SunShangXiang",
Age: 16,
}
//db.Create(p1)
result := db.Create(p1)
fmt.Println(result.Value)
}
func connect() (db *gorm.DB,err error) {
db, err = gorm.Open("mysql", "root:40010355@tcp(127.0.0.1:3306)/crow?charset=utf8&parseTime=True&loc=Local")
if err != nil {
fmt.Printf(err.Error())
defer db.Close()
}else {
fmt.Printf("OK\n")
db.DB().SetMaxIdleConns(10)
db.DB().SetMaxOpenConns(100)
}
return
}
- 创建数据结果
mysql> select * from users;
+----+--------+------+
| id | name | age |
+----+--------+------+
| 1 | LiuBei | 28 |
+----+--------+------+
1 row in set (0.00 sec)
mysql> select * from spouses;
+----+---------------+------+---------+
| id | name | age | user_id |
+----+---------------+------+---------+
| 4 | SunShangXiang | 16 | 1 |
+----+---------------+------+---------+
1 row in set (0.00 sec)
如上可见,同时在两张表里写入了数据,外键spouses.user_id关联了users.id
1.4 用外键查询
利用&User{ID: 1} 查询spouses表中的数据。
func main() {
db,_ := connect()
defer db.Close()
var spouse Spouse
db.Model(&User{ID: 1}).Related(&spouse)
fmt.Println(spouse)
}
输出结果
OK
{SunShangXiang {0 0} 1 16}
1.5 自定义外键名
如前所述,默认外键名为 “表名+ 关联外键名",其对应结构体成员为 User+ID 即UserID
如果我们要自定义,则使用foreignkey
指定,如下:
type User struct {
//gorm.Model
ID int64
Name string
Age int64
}
type Spouse struct {
//gorm.Model
Name string
User User `gorm:"foreignkey:HusbandID"`
HusbandID int64
Age int64
}
1.6 自定义关联外键
关联外键默认使用主键,即users表的id。如果要自定义,则修改如下:
type User struct {
//gorm.Model
ID int64
Name string
Age int64
}
type Spouse struct {
//gorm.Model
Name string
User User `gorm:"association_foreignkey:Name"`
UserName string
Age int64
}
2. HasOne
2.1 创建模型
和 BelongsTo几乎相同,都是一对一关联,且Spouse模型属于User模型(即Spouse的外键关联到User指定列)
不同仅是两个模型谁引用谁。但都是谁引用就用谁创建数据。
替换 "1.3 完整示例" 中两个结构体
type User struct {
//gorm.Model
ID int64
Name string
Age int64
Spouse Spouse
}
type Spouse struct {
//gorm.Model
Name string
Age int64
UserID int64
}
2.2 创建数据
- 代码
替换 "1.3 完整示例" 中main函数
func main() {
db,_ := connect()
defer db.Close()
p1 := &User{
Name: "ZhangFei",
Age: 22,
Spouse: Spouse{
Name: "XiaHouJuan",
Age: 18,
},
}
result := db.Create(p1)
fmt.Println(result.Value)
}
- 输出
OK
&{6 ZhangFei 22 {XiaHouJuan 18 6}}
- 表中数据
mysql> select * from users;
+----+----------+------+-----------+
| id | name | age | spouse_id |
+----+----------+------+-----------+
| 6 | ZhangFei | 22 | NULL |
+----+----------+------+-----------+
1 row in set (0.00 sec)
mysql> select * from spouses;
+----+------------+------+---------+
| id | name | age | user_id |
+----+------------+------+---------+
| 2 | XiaHouJuan | 18 | 6 |
+----+------------+------+---------+
1 row in set (0.00 sec)
2.3 修改外键
默认外键名 被关联表名+被关联列名,我们可以作出如下修改,使得spouses.user_name关联到users.name
type User struct {
//gorm.Model
ID int64
Name string
Age int64
Spouse Spouse `gorm:"foreignkey:user_name;association_foreignkey:name"`
}
type Spouse struct {
//gorm.Model
Name string
Age int64
UserName string
}
- 数据修改结果
mysql> select * from spouses;
+----+------------+------+-----------+
| id | name | age | user_name |
+----+------------+------+-----------+
| 3 | XiaHouJuan | 18 | ZhangFei |
+----+------------+------+-----------+
1 row in set (0.00 sec)
mysql> select * from users;
+----+----------+------+
| id | name | age |
+----+----------+------+
| 7 | ZhangFei | 22 |
+----+----------+------+
1 row in set (0.00 sec)
2.4 使用外键查询
db.Model(&User{ID: 10}).Related(&spouse,"user_id")
通过User.ID的值,查spouse表的内容
- 示例
表内容
mysql> mysql> select users;
+----+----------+------+
| id | name | age |
+----+----------+------+
| 10 | ZhangFei | 22 |
+----+----------+------+
1 row in set (0.00 sec)
mysql> select * from spouses;
+----+------------+------+-----------+---------+
| id | name | age | user_name | user_id |
+----+------------+------+-----------+---------+
| 4 | XiaHouJuan | 18 | NULL | 10 |
+----+------------+------+-----------+---------+
1 row in set (0.00 sec)
代码
func main() {
db,_ := connect()
defer db.Close()
var spouse Spouse
db.Model(&User{ID: 10}).Related(&spouse,"user_id")
fmt.Println(spouse)
}
查询结果
OK
{XiaHouJuan 18 10}
网友评论