一、概述
HasOne
与另外一个模型建立一对一的关联,这种关联表明一个模型的每个实例都包含或拥有另一个模型实例。
二、模型建立
-
实现
HasOne
模型,拥有者需要定义被拥有者的模型变量(关联模型变量),并在模型变量中指定:(1) 外键:在被拥有者模型中定义,在关联模型变量中标注。默认为
拥有者模型名ID
,需要在关联模型中显式定义。(2) 引用:在拥有者模型中定义,类型要与外键变量的类型一致,在关联模型变量中标注,默认为关联模型的主键。
-
以用户
User
拥有CreditCard
为例,模型定义如下:(1)
CreditCard
为关联模型变量,外键默认为CreditCard
模型的UserID
,引用为User
模型的ID
。// 拥有者模型。 type User struct { ID uint `gorm:"primary_key"` // 默认的引用 Password string `gorm:"->:false;<-"` CreditCard CreditCard // 关联模型变量。 } // 关联模型。 type CreditCard struct { ID uint `gorm:"primary_key"` UserID uint // 默认的外键,需要显式定义。 Number string `gorm:"type:varchar(20)"` }
(2) 建表之后,在
CredictCard
表中,会新增一个字段user_id
,表示该CreditCard
记录与之关联的User
主键。User
表字段描述
CreditCard
表字段描述
三、重定义
1. 重定义外键
- 重定义外键,即在关联模型中指向引用的字段,需要在关联模型变量中标注。
- 如下重定义
UserRefer
为外键,使用foreignKey
标注关联模型变量CreditCard
。
type User struct {
ID uint `gorm:"primary_key"`
Name string
Password string `gorm:"->:false;<-"`
CreditCard CreditCard `gorm:"foreignKey:UserRefer"`
}
type CreditCard struct {
ID uint `gorm:"primary_key"`
UserRefer uint
Number string `gorm:"type:varchar(20)"`
}
2. 重定义引用
- 重定义引用,即外键指向的标识,需要在关联模型变量中标注。
- 如下重定义
Name
为引用。
type User struct {
ID uint `gorm:"primary_key"`
Name string
Password string `gorm:"->:false;<-"`
CreditCard CreditCard `gorm:"foreignKey:UserName;references:Name"`
}
type CreditCard struct {
ID uint `gorm:"primary_key"`
UserName string
Number string `gorm:"type:varchar(20)"`
}
四、相关操作
- 下列的操作基于以下的
HasOne
关联模型
type User struct {
ID uint `gorm:"primary_key"`
Name string
Password string `gorm:"->:false;<-"`
CreditCard CreditCard `gorm:"foreignKey:UserName;references:Name"`
}
type CreditCard struct {
ID uint `gorm:"primary_key"`
UserName string
Number string `gorm:"type:varchar(20)"`
}
1. 保存
- 声明完整的结构体变量,调用
Save
方法进行保存。
func TestSaveUser() {
user := User{
Name: "Jason",
Password: "12345",
CreditCard: CreditCard{
Number: "1234567890",
},
}
err := SaveUser(user)
if err != nil {
log.Println("用户保存失败!")
} else {
log.Println("用户保存成功!")
}
}
func SaveUser(user User) error {
err := db.Save(&user).Error
return err
}
2. 删除
- 删除实例有两种策略:
(1) 连同HasOne
关联的对象记录删除,如上删除用户后连同账号记录一同删除。采用Select
方法。如下,使用Select
方法选择关联的模型,连同模型记录一同删除。
func DeleteUserByName(name string) error {
var user User
var err error
db.Model(&user).Where("name = ?", name).First(&user)
err = db.Model(&user).Select("CreditCard").Delete(&user).Error
return err
}
(2) 不删除关联的模型记录,与(1)类型,不使用Select
方法。
3. 查询
-
在查询时需要加载关联模型,使用
Preload
方法加载。func GetUserByName(name string) (User, error) { var user User err := db.Model(&user).Preload("CreditCard").Where("name = ?", name).First(&user).Error return user, err }