關聯

自動建立/更新

GORM 在建立或更新記錄時,會自動儲存關聯及其參考,並使用主要更新現有關聯的外來金鑰參考的插入更新技術。

在建立時自動儲存關聯

當您建立新記錄時,GORM 會自動儲存其關聯資料。這包括將資料插入相關表格和管理外來金鑰參考。

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"},
},
}

// Creating a user along with its associated addresses, emails, and languages
db.Create(&user)
// BEGIN TRANSACTION;
// INSERT INTO "addresses" (address1) VALUES ("Billing Address - Address 1"), ("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"), (111, "jinzhu-2@example.com") ON DUPLICATE KEY DO NOTHING;
// INSERT INTO "languages" ("name") VALUES ('ZH'), ('EN') ON DUPLICATE KEY DO NOTHING;
// INSERT INTO "user_languages" ("user_id","language_id") VALUES (111, 1), (111, 2) ON DUPLICATE KEY DO NOTHING;
// COMMIT;

db.Save(&user)

使用 FullSaveAssociations 更新關聯

對於需要完整更新關聯資料(不只是外來金鑰參考)的情況,應使用 FullSaveAssociations 模式。

// Update a user and fully update all its associations
db.Session(&gorm.Session{FullSaveAssociations: true}).Updates(&user)
// SQL: Fully updates addresses, users, emails tables, including existing associated records

使用 FullSaveAssociations 可確保模型的完整狀態(包括其所有關聯)反映在資料庫中,並在整個應用程式中維護資料完整性和一致性。

略過自動建立/更新

GORM 提供彈性,可以在建立或更新作業期間略過關聯的自動儲存。這可以使用 SelectOmit 方法來達成,這些方法讓您可以明確指定哪些欄位或關聯應包含或排除在作業中。

使用 Select 來包含特定欄位

Select 方法讓您可以指定模型的哪些欄位應該儲存。這表示只有選取的欄位會包含在 SQL 操作中。

user := User{
// User and associated data
}

// Only include the 'Name' field when creating the user
db.Select("Name").Create(&user)
// SQL: INSERT INTO "users" (name) VALUES ("jinzhu");

使用 Omit 來排除欄位或關聯

相反地,Omit 允許您在儲存模型時排除某些欄位或關聯。

// Skip creating the 'BillingAddress' when creating the user
db.Omit("BillingAddress").Create(&user)

// Skip all associations when creating the user
db.Omit(clause.Associations).Create(&user)

注意
對於多對多的關聯,GORM 會在建立連接資料表參考之前更新關聯。若要略過此更新,請將 Omit 與關聯名稱後接 .* 一起使用

// Skip upserting 'Languages' associations
db.Omit("Languages.*").Create(&user)

若要略過建立關聯及其參考

// Skip creating 'Languages' associations and their references
db.Omit("Languages").Create(&user)

使用 SelectOmit,您可以微調 GORM 處理模型建立或更新的方式,讓您可以控制關聯的自動儲存行為。

Select/Omit 關聯欄位

在 GORM 中,在建立或更新記錄時,您可以使用 SelectOmit 方法來特別包含或排除關聯模型的某些欄位。

使用 Select,您可以指定在儲存主要模型時應包含關聯模型的哪些欄位。這對於選擇性儲存關聯的某些部分特別有用。

相反地,Omit 讓您可以排除關聯模型的某些欄位,使其不予儲存。當您想要防止關聯的特定部分被持續時,這會很有用。

user := User{
Name: "jinzhu",
BillingAddress: Address{Address1: "Billing Address - Address 1", Address2: "addr2"},
ShippingAddress: Address{Address1: "Shipping Address - Address 1", Address2: "addr2"},
}

// Create user and his BillingAddress, ShippingAddress, including only specified fields of BillingAddress
db.Select("BillingAddress.Address1", "BillingAddress.Address2").Create(&user)
// SQL: Creates user and BillingAddress with only 'Address1' and 'Address2' fields

// Create user and his BillingAddress, ShippingAddress, excluding specific fields of BillingAddress
db.Omit("BillingAddress.Address2", "BillingAddress.CreatedAt").Create(&user)
// SQL: Creates user and BillingAddress, omitting 'Address2' and 'CreatedAt' fields

刪除關聯

GORM 允許在刪除主要記錄時使用 Select 方法刪除特定的關聯關係(has one、has many、many2many)。此功能對於維護資料庫完整性以及確保相關資料在刪除時得到適當管理特別有用。

您可以使用 Select 指定應與主要記錄一起刪除哪些關聯。

// Delete a user's account when deleting the user
db.Select("Account").Delete(&user)

// Delete a user's Orders and CreditCards associations when deleting the user
db.Select("Orders", "CreditCards").Delete(&user)

// Delete all of a user's has one, has many, and many2many associations
db.Select(clause.Associations).Delete(&user)

// Delete each user's account when deleting multiple users
db.Select("Account").Delete(&users)

注意
重要的是要注意,只有在刪除記錄的主鍵不為零時,關聯才會被刪除。GORM 使用這些主鍵作為條件來刪除選取的關聯。

// This will not work as intended
db.Select("Account").Where("name = ?", "jinzhu").Delete(&User{})
// SQL: Deletes all users with name 'jinzhu', but their accounts won't be deleted

// Correct way to delete a user and their account
db.Select("Account").Where("name = ?", "jinzhu").Delete(&User{ID: 1})
// SQL: Deletes the user with name 'jinzhu' and ID '1', and the user's account

// Deleting a user with a specific ID and their account
db.Select("Account").Delete(&User{ID: 1})
// SQL: Deletes the user with ID '1', and the user's account

關聯模式

GORM 中的關聯模式提供各種輔助方法來處理模型之間的關聯,提供一種管理關聯資料的有效方式。

若要啟動關聯模式,請指定來源模型和關聯欄位名稱。來源模型必須包含主鍵,而關聯欄位名稱應與現有關聯相符。

var user User
db.Model(&user).Association("Languages")
// Check for errors
error := db.Model(&user).Association("Languages").Error

尋找關聯

擷取關聯記錄,可搭配或不搭配其他條件。

// Simple find
db.Model(&user).Association("Languages").Find(&languages)

// Find with conditions
codes := []string{"zh-CN", "en-US", "ja-JP"}
db.Model(&user).Where("code IN ?", codes).Association("Languages").Find(&languages)

附加關聯

新增 `多對多`、`多對一` 的新關聯,或取代 `一對一`、`一對多` 的目前關聯。

// Append new languages
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"})

取代關聯

以新關聯取代目前的關聯。

// Replace existing languages
db.Model(&user).Association("Languages").Replace([]Language{languageZH, languageEN})

db.Model(&user).Association("Languages").Replace(Language{Name: "DE"}, languageEN)

刪除關聯

移除來源與參數之間的關聯,僅刪除參考。

// Delete specific languages
db.Model(&user).Association("Languages").Delete([]Language{languageZH, languageEN})

db.Model(&user).Association("Languages").Delete(languageZH, languageEN)

清除關聯

移除來源與關聯之間的所有參考。

// Clear all languages
db.Model(&user).Association("Languages").Clear()

計算關聯

取得目前關聯的數量,可搭配或不搭配條件。

// Count all languages
db.Model(&user).Association("Languages").Count()

// Count with conditions
codes := []string{"zh-CN", "en-US", "ja-JP"}
db.Model(&user).Where("code IN ?", codes).Association("Languages").Count()

批次資料處理

關聯模式允許您批次處理多筆記錄的關聯。這包括尋找、附加、取代、刪除和計算關聯資料的作業。

  • 尋找關聯:擷取一組記錄的關聯資料。
db.Model(&users).Association("Role").Find(&roles)
  • 刪除關聯:移除多筆記錄中的特定關聯。
db.Model(&users).Association("Team").Delete(&userA)
  • 計算關聯:取得一批記錄的關聯數量。
db.Model(&users).Association("Team").Count()
  • 附加/取代關聯:管理多筆記錄的關聯。請注意參數長度必須與資料相符。
var users = []User{user1, user2, user3}

// Append different teams to different users in a batch
// Append userA to user1's team, userB to user2's team, and userA, userB, userC to user3's team
db.Model(&users).Association("Team").Append(&userA, &userB, &[]User{userA, userB, userC})

// Replace teams for multiple users in a batch
// Reset user1's team to userA, user2's team to userB, and user3's team to userA, userB, and userC
db.Model(&users).Association("Team").Replace(&userA, &userB, &[]User{userA, userB, userC})

刪除關聯記錄

在 GORM 中,關聯模式中的 ReplaceDeleteClear 方法主要影響外鍵參考,而不是關聯記錄本身。了解和管理此行為對於資料完整性至關重要。

  • 參考更新:這些方法將關聯的外鍵更新為 null,有效地移除來源和關聯模型之間的連結。
  • 沒有實體記錄刪除:實際的關聯記錄在資料庫中保持不變。

使用 Unscoped 修改刪除行為

對於需要實際刪除關聯記錄的場景,Unscoped 方法會改變此行為。

  • 軟刪除:將關聯記錄標記為已刪除(設定 deleted_at 欄位),而不將它們從資料庫中移除。
db.Model(&user).Association("Languages").Unscoped().Clear()
  • 永久刪除:從資料庫中實體刪除關聯記錄。
// db.Unscoped().Model(&user)
db.Unscoped().Model(&user).Association("Languages").Unscoped().Clear()

關聯標籤

GORM 中的關聯標籤用於指定如何處理模型之間的關聯。這些標籤定義關係的詳細資訊,例如外鍵、參考和約束。了解這些標籤對於有效設定和管理關係至關重要。

標籤 說明
foreignKey 指定當前模型中用作聯結表格中外鍵的欄位名稱。
references 指出聯結表格的外鍵對應到的參考表格中的欄位名稱。
polymorphic 定義多型別,通常是模型名稱。
polymorphicValue 設定多型別值,通常是表格名稱(如果沒有另行指定)。
many2many 命名在多對多關係中使用的聯結表格。
joinForeignKey 識別聯結表格中對應回當前模型表格的外鍵欄位。
joinReferences 指向聯結表格中連結到參考模型表格的外鍵欄位。
constraint 指定關聯的關聯約束,例如 OnUpdateOnDelete

白金贊助商

黃金贊助商

白金贊助商

黃金贊助商