# 實體關聯
## 自動創建、更新
在創建、更新記錄時,GORM 會通過 [Upsert](../CRUD接口/create.html#upsert) 自動保存關聯及其引用記錄。
```go
user := User{
Name: "jinzhu",
BillingAddress: Address{Address1: "Billing Address - Address 1"},
ShippingAddress: Address{Address1: "Shipping Address - Address 1"},
Emails: []Email{
{Email: "jinzhu@example.com"},
{Email: "jinzhu-2@example.com"},
},
Languages: []Language{
{Name: "ZH"},
{Name: "EN"},
},
}
db.Create(&user)
// BEGIN TRANSACTION;
// INSERT INTO "addresses" (address1) VALUES ("Billing Address - Address 1") ON DUPLICATE KEY DO NOTHING;
// INSERT INTO "addresses" (address1) VALUES ("Shipping Address - Address 1") ON DUPLICATE KEY DO NOTHING;
// INSERT INTO "users" (name,billing_address_id,shipping_address_id) VALUES ("jinzhu", 1, 2);
// INSERT INTO "emails" (user_id,email) VALUES (111, "jinzhu@example.com") ON DUPLICATE KEY DO NOTHING;
// INSERT INTO "emails" (user_id,email) VALUES (111, "jinzhu-2@example.com") ON DUPLICATE KEY DO NOTHING;
// INSERT INTO "languages" ("name") VALUES ('ZH') ON DUPLICATE KEY DO NOTHING;
// INSERT INTO "user_languages" ("user_id","language_id") VALUES (111, 1) ON DUPLICATE KEY DO NOTHING;
// INSERT INTO "languages" ("name") VALUES ('EN') ON DUPLICATE KEY DO NOTHING;
// INSERT INTO user_languages ("user_id","language_id") VALUES (111, 2) ON DUPLICATE KEY DO NOTHING;
// COMMIT;
db.Save(&user)
```
## 跳過自動創建、更新
若要在創建、更新時跳過自動保存,您可以使用 `Select` 或 `Omit`,例如:
```go
user := User{
Name: "jinzhu",
BillingAddress: Address{Address1: "Billing Address - Address 1"},
ShippingAddress: Address{Address1: "Shipping Address - Address 1"},
Emails: []Email{
{Email: "jinzhu@example.com"},
{Email: "jinzhu-2@example.com"},
},
Languages: []Language{
{Name: "ZH"},
{Name: "EN"},
},
}
db.Select("Name").Create(&user)
// INSERT INTO "users" (name) VALUES ("jinzhu", 1, 2);
db.Omit("BillingAddress").Create(&user)
// 創建 user 時,跳過自動創建 BillingAddress
db.Omit(clause.Associations).Create(&user)
// 創建 user 時,跳過自動創建所有關聯記錄
```
## 關聯模式
關聯模式包含一些在處理關系時有用的方法
```go
// 開始關聯模式
var user User
db.Model(&user).Association("Languages")
// `user` 是源模型,它的主鍵不能為空
// 關系的字段名是 `Languages`
// 如果上面兩個條件匹配,會開始關聯模式,否則會返回錯誤
db.Model(&user).Association("Languages").Error
```
### 查找關聯
查找所有匹配的關聯記錄
```go
db.Model(&user).Association("Languages").Find(&languages)
// 帶條件的查找
codes := []string{"zh-CN", "en-US", "ja-JP"}
db.Model(&user).Where("code IN ?", codes).Association("Languages").Find(&languages)
```
### 添加關聯
為 `many to many`、`has many` 添加新的關聯;為 `has one`, `belongs to` 替換當前的關聯
```go
db.Model(&user).Association("Languages").Append([]Language{languageZH, languageEN})
db.Model(&user).Association("Languages").Append(Language{Name: "DE"})
db.Model(&user).Association("CreditCard").Append(CreditCard{Number: "411111111111"})
```
### 替換關聯
用一個新的關聯替換當前的關聯
```go
db.Model(&user).Association("Languages").Replace([]Language{languageZH, languageEN})
db.Model(&user).Association("Languages").Replace(Language{Name: "DE"}, languageEN)
```
### 刪除關聯
如果存在,則刪除源模型與參數之間的關系,只會刪除引用,不會從數據庫中刪除這些對象。
```go
db.Model(&user).Association("Languages").Delete([]Language{languageZH, languageEN})
db.Model(&user).Association("Languages").Delete(languageZH, languageEN)
```
### 清空關聯
刪除源模型與關聯之間的所有引用,但不會刪除這些關聯
```go
db.Model(&user).Association("Languages").Clear()
```
### 關聯計數
返回當前關聯的計數
```go
db.Model(&user).Association("Languages").Count()
```
### 批量處理數據
關聯模式支持批量處理數據,例如:
```go
// 查詢所有用戶的所有角色
db.Model(&users).Association("Role").Find(&roles)
// 將 userA 移出所有的 Team
db.Model(&users).Association("Team").Delete(&userA)
// 獲取所有 Team 成員的不重復計數
db.Model(&users).Association("Team").Count()
// 對于 `Append`、`Replace` 的批量處理,參數與數據的長度必須相等,否則會返回錯誤
var users = []User{user1, user2, user3}
// 例如:我們有 3 個 user,將 userA 添加到 user1 的 Team,將 userB 添加到 user2 的 Team,將 userA、userB、userC 添加到 user3 的 Team
db.Model(&users).Association("Team").Append(&userA, &userB, &[]User{userA, userB, userC})
// 將 user1 的 Team 重置為 userA,將 user2的 team 重置為 userB,將 user3 的 team 重置為 userA、userB 和 userC
db.Model(&users).Association("Team").Replace(&userA, &userB, &[]User{userA, userB, userC})
```
## 關聯標簽
| 標簽 | 描述 |
| :--------------- | :------------------- |
| foreignKey | 指定外鍵 |
| references | 指定引用 |
| polymorphic | 指定多態類型 |
| polymorphicValue | 指定多態值、默認表名 |
| many2many | 指定連接表表名 |
| jointForeignKey | 指定連接表的外鍵 |
| joinReferences | 指定連接表的引用外鍵 |
| constraint | 關系約束 |