关联

自动创建/更新

GORM 在创建或更新记录时,使用主要更新现有关联的外键引用的更新插入技术,自动保存关联及其引用。

创建时自动保存关联

创建新记录时,GORM 会自动保存其关联数据。这包括将数据插入相关表和管理外键引用。

user := User{
Name: "jinzhu",
BillingAddress: Address{Address1: "Billing Address - Address 1"},
ShippingAddress: Address{Address1: "Shipping Address - Address 1"},
Emails: []Email{
{Email: "[email protected]"},
{Email: "[email protected]"},
},
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, "[email protected]"), (111, "[email protected]") 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 处理模型创建或更新的方式,从而控制关联的自动保存行为。

选择/省略关联字段

在 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 方法删除特定的关联关系(一对一、一对多、多对多)。此功能对于维护数据库完整性和确保在删除时适当地管理相关数据特别有用。

您可以使用 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 方法主要影响外键引用,而不是关联记录本身。理解和管理此行为对于数据完整性至关重要。

  • 引用更新:这些方法将关联的外键更新为空,有效地删除了源模型和关联模型之间的链接。
  • 不进行物理记录删除:实际的关联记录在数据库中保持不变。

使用 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

铂金赞助商

黄金赞助商

铂金赞助商

黄金赞助商