# Has One
## Has One
`has one` 与另一个模型建立一对一的关联,但它和一对一关系有些许不同。 这种关联表明一个模型的每个实例都包含或拥有另一个模型的一个实例。
例如,您的应用包含 user 和 credit card 模型,且每个 user 只能有一张 credit card。
```go
// User 有一张 CreditCard,CreditCardID 是外键
type User struct {
gorm.Model
CreditCard CreditCard
}
type CreditCard struct {
gorm.Model
Number string
UserID uint
}
```
## 重写外键
对于 `has one` 关系,同样必须存在外键字段。拥有者将把属于它的模型的主键保存到这个字段。
这个字段的名称通常由 `has one` 模型的类型加上其 `主键` 生成,对于上面的例子,它是 `UserID`。
为 user 添加 credit card 时,它会将 user 的 `ID` 保存到自己的 `UserID` 字段。
如果你想要使用另一个字段来保存该关系,你同样可以使用标签 `foreignKey` 来更改它,例如:
```go
type User struct {
gorm.Model
CreditCard CreditCard `gorm:"foreignKey:UserName"`
// 使用 UserName 作为外键
}
type CreditCard struct {
gorm.Model
Number string
UserName string
}
```
## 重写引用
默认情况下,拥有者实体会将 `has one` 对应模型的主键保存为外键,您也可以修改它,用另一个字段来保存,例如下个这个使用 `Name` 来保存的例子。
您可以使用标签 `references` 来更改它,例如:
```go
type User struct {
gorm.Model
Name string `sql:"index"`
CreditCard CreditCard `gorm:"foreignkey:UserName;references:name"`
}
type CreditCard struct {
gorm.Model
Number string
UserName string
}
```
## 多态关联
GORM 为 `has one` 和 `has many` 提供了多态关联支持,它会将拥有者实体的表名、主键都保存到多态类型的字段中。
```go
type Cat struct {
ID int
Name string
Toy Toy `gorm:"polymorphic:Owner;"`
}
type Dog struct {
ID int
Name string
Toy Toy `gorm:"polymorphic:Owner;"`
}
type Toy struct {
ID int
Name string
OwnerID int
OwnerType string
}
db.Create(&Dog{Name: "dog1", Toy: Toy{Name: "toy1"}})
// INSERT INTO `dogs` (`name`) VALUES ("dog1")
// INSERT INTO `toys` (`name`,`owner_id`,`owner_type`) VALUES ("toy1","1","dogs")
```
您可以使用标签 `polymorphicValue` 来更改多态类型的值,例如:
```go
type Dog struct {
ID int
Name string
Toy Toy `gorm:"polymorphic:Owner;polymorphicValue:master"`
}
type Toy struct {
ID int
Name string
OwnerID int
OwnerType string
}
db.Create(&Dog{Name: "dog1", Toy: Toy{Name: "toy1"}})
// INSERT INTO `dogs` (`name`) VALUES ("dog1")
// INSERT INTO `toys` (`name`,`owner_id`,`owner_type`) VALUES ("toy1","1","master")
```
## Has One 的 CURD
查看 [关联模式](./associations.md#Association-Mode) 获取 `has one` 相关的用法
## 预加载
GORM 可以通过 `Preload`、`Joins` 预加载 `has one` 关联的记录,查看 [预加载](./preload.md) 获取详情
## 自引用 Has One
```go
type User struct {
gorm.Model
Name string
ManagerID *uint
Manager *User
}
```
## 外键约束
你可以通过标签 `constraint` 并带上 `OnUpdate`、`OnDelete` 实现外键约束,例如:
```go
type User struct {
gorm.Model
CreditCard CreditCard `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
}
type CreditCard struct {
gorm.Model
Number string
UserID uint
}
```