Auto Create/Update

GORM automates the saving of associations and their references when creating or updating records, using an upsert technique that primarily updates foreign key references for existing associations.

Auto-Saving Associations on Create

When you create a new record, GORM will automatically save its associated data. This includes inserting data into related tables and managing foreign key references.

  1. user := User{
  2. Name: "jinzhu",
  3. BillingAddress: Address{Address1: "Billing Address - Address 1"},
  4. ShippingAddress: Address{Address1: "Shipping Address - Address 1"},
  5. Emails: []Email{
  6. {Email: "[email protected]"},
  7. {Email: "[email protected]"},
  8. },
  9. Languages: []Language{
  10. {Name: "ZH"},
  11. {Name: "EN"},
  12. },
  13. }
  14. // Creating a user along with its associated addresses, emails, and languages
  15. db.Create(&user)
  16. // BEGIN TRANSACTION;
  17. // INSERT INTO "addresses" (address1) VALUES ("Billing Address - Address 1"), ("Shipping Address - Address 1") ON DUPLICATE KEY DO NOTHING;
  18. // INSERT INTO "users" (name,billing_address_id,shipping_address_id) VALUES ("jinzhu", 1, 2);
  19. // INSERT INTO "emails" (user_id,email) VALUES (111, "[email protected]"), (111, "[email protected]") ON DUPLICATE KEY DO NOTHING;
  20. // INSERT INTO "languages" ("name") VALUES ('ZH'), ('EN') ON DUPLICATE KEY DO NOTHING;
  21. // INSERT INTO "user_languages" ("user_id","language_id") VALUES (111, 1), (111, 2) ON DUPLICATE KEY DO NOTHING;
  22. // COMMIT;
  23. db.Save(&user)

Updating Associations with FullSaveAssociations

For scenarios where a full update of the associated data is required (not just the foreign key references), the FullSaveAssociations mode should be used.

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

Using FullSaveAssociations ensures that the entire state of the model, including all its associations, is reflected in the database, maintaining data integrity and consistency throughout the application.

Skip Auto Create/Update

GORM provides flexibility to skip automatic saving of associations during create or update operations. This can be achieved using the Select or Omit methods, which allow you to specify exactly which fields or associations should be included or excluded in the operation.

Using Select to Include Specific Fields

The Select method lets you specify which fields of the model should be saved. This means that only the selected fields will be included in the SQL operation.

  1. user := User{
  2. // User and associated data
  3. }
  4. // Only include the 'Name' field when creating the user
  5. db.Select("Name").Create(&user)
  6. // SQL: INSERT INTO "users" (name) VALUES ("jinzhu");

Using Omit to Exclude Fields or Associations

Conversely, Omit allows you to exclude certain fields or associations when saving a model.

  1. // Skip creating the 'BillingAddress' when creating the user
  2. db.Omit("BillingAddress").Create(&user)
  3. // Skip all associations when creating the user
  4. db.Omit(clause.Associations).Create(&user)

NOTE:
For many-to-many associations, GORM upserts the associations before creating join table references. To skip this upserting, use Omit with the association name followed by .*:

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

To skip creating both the association and its references:

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

Using Select and Omit, you can fine-tune how GORM handles the creation or updating of your models, giving you control over the auto-save behavior of associations.

Select/Omit Association fields

In GORM, when creating or updating records, you can use the Select and Omit methods to specifically include or exclude certain fields of an associated model.

With Select, you can specify which fields of an associated model should be included when saving the primary model. This is particularly useful for selectively saving parts of an association.

Conversely, Omit lets you exclude certain fields of an associated model from being saved. This can be useful when you want to prevent specific parts of an association from being persisted.

  1. user := User{
  2. Name: "jinzhu",
  3. BillingAddress: Address{Address1: "Billing Address - Address 1", Address2: "addr2"},
  4. ShippingAddress: Address{Address1: "Shipping Address - Address 1", Address2: "addr2"},
  5. }
  6. // Create user and his BillingAddress, ShippingAddress, including only specified fields of BillingAddress
  7. db.Select("BillingAddress.Address1", "BillingAddress.Address2").Create(&user)
  8. // SQL: Creates user and BillingAddress with only 'Address1' and 'Address2' fields
  9. // Create user and his BillingAddress, ShippingAddress, excluding specific fields of BillingAddress
  10. db.Omit("BillingAddress.Address2", "BillingAddress.CreatedAt").Create(&user)
  11. // SQL: Creates user and BillingAddress, omitting 'Address2' and 'CreatedAt' fields

Delete Associations

GORM allows for the deletion of specific associated relationships (has one, has many, many2many) using the Select method when deleting a primary record. This feature is particularly useful for maintaining database integrity and ensuring related data is appropriately managed upon deletion.

You can specify which associations should be deleted along with the primary record by using Select.

  1. // Delete a user's account when deleting the user
  2. db.Select("Account").Delete(&user)
  3. // Delete a user's Orders and CreditCards associations when deleting the user
  4. db.Select("Orders", "CreditCards").Delete(&user)
  5. // Delete all of a user's has one, has many, and many2many associations
  6. db.Select(clause.Associations).Delete(&user)
  7. // Delete each user's account when deleting multiple users
  8. db.Select("Account").Delete(&users)

NOTE:
It’s important to note that associations will be deleted only if the primary key of the deleting record is not zero. GORM uses these primary keys as conditions to delete the selected associations.

  1. // This will not work as intended
  2. db.Select(“Account”).Where(“name = ?”, jinzhu”).Delete(&User{})
  3. // 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

Association Mode

Association Mode in GORM offers various helper methods to handle relationships between models, providing an efficient way to manage associated data.

To start Association Mode, specify the source model and the relationship’s field name. The source model must contain a primary key, and the relationship’s field name should match an existing association.

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

Finding Associations

Retrieve associated records with or without additional conditions.

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

Appending Associations

Add new associations for many to many, has many, or replace the current association for has one, belongs to.

  1. // Append new languages
  2. db.Model(&user).Association("Languages").Append([]Language{languageZH, languageEN})
  3. db.Model(&user).Association("Languages").Append(&Language{Name: "DE"})
  4. db.Model(&user).Association("CreditCard").Append(&CreditCard{Number: "411111111111"})

Replacing Associations

Replace current associations with new ones.

  1. // Replace existing languages
  2. db.Model(&user).Association("Languages").Replace([]Language{languageZH, languageEN})
  3. db.Model(&user).Association("Languages").Replace(Language{Name: "DE"}, languageEN)

Deleting Associations

Remove the relationship between the source and arguments, only deleting the reference.

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

Clearing Associations

Remove all references between the source and association.

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

Counting Associations

Get the count of current associations, with or without conditions.

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

Batch Data Handling

Association Mode allows you to handle relationships for multiple records in a batch. This includes finding, appending, replacing, deleting, and counting operations for associated data.

  • Finding Associations: Retrieve associated data for a collection of records.
  1. db.Model(&users).Association("Role").Find(&roles)
  • Deleting Associations: Remove specific associations across multiple records.
  1. db.Model(&users).Association("Team").Delete(&userA)
  • Counting Associations: Get the count of associations for a batch of records.
  1. db.Model(&users).Association("Team").Count()
  • Appending/Replacing Associations: Manage associations for multiple records. Note the need for matching argument lengths with the data.
  1. var users = []User{user1, user2, user3}
  2. // Append different teams to different users in a batch
  3. // Append userA to user1's team, userB to user2's team, and userA, userB, userC to user3's team
  4. db.Model(&users).Association("Team").Append(&userA, &userB, &[]User{userA, userB, userC})
  5. // Replace teams for multiple users in a batch
  6. // Reset user1's team to userA, user2's team to userB, and user3's team to userA, userB, and userC
  7. db.Model(&users).Association("Team").Replace(&userA, &userB, &[]User{userA, userB, userC})

Delete Association Record

In GORM, the Replace, Delete, and Clear methods in Association Mode primarily affect the foreign key references, not the associated records themselves. Understanding and managing this behavior is crucial for data integrity.

  • Reference Update: These methods update the association’s foreign key to null, effectively removing the link between the source and associated models.
  • No Physical Record Deletion: The actual associated records remain untouched in the database.

Modifying Deletion Behavior with Unscoped

For scenarios requiring actual deletion of associated records, the Unscoped method alters this behavior.

  • Soft Delete: Marks associated records as deleted (sets deleted_at field) without removing them from the database.
  1. db.Model(&user).Association("Languages").Unscoped().Clear()
  • Permanent Delete: Physically deletes the association records from the database.
  1. // db.Unscoped().Model(&user)
  2. db.Unscoped().Model(&user).Association("Languages").Unscoped().Clear()

Association Tags

Association tags in GORM are used to specify how associations between models are handled. These tags define the relationship’s details, such as foreign keys, references, and constraints. Understanding these tags is essential for setting up and managing relationships effectively.

TagDescription
foreignKeySpecifies the column name of the current model used as a foreign key in the join table.
referencesIndicates the column name in the reference table that the foreign key of the join table maps to.
polymorphicDefines the polymorphic type, typically the model name.
polymorphicValueSets the polymorphic value, usually the table name, if not specified otherwise.
many2manyNames the join table used in a many-to-many relationship.
joinForeignKeyIdentifies the foreign key column in the join table that maps back to the current model’s table.
joinReferencesPoints to the foreign key column in the join table that links to the reference model’s table.
constraintSpecifies relational constraints like OnUpdate, OnDelete for the association.