Auto Create/Update
GORM will auto-save associations and its reference using Upsert when creating/updating a record.
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: "jinzhu@example.com"},
7. {Email: "jinzhu-2@example.com"},
8. },
9. Languages: []Language{
10. {Name: "ZH"},
11. {Name: "EN"},
12. },
13. }
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, "jinzhu@example.com"), (111, "jinzhu-2@example.com") 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;
24. db.Save(&user)
If you want to update associations’s data, you should use the FullSaveAssociations mode:
1. db.Session(&gorm.Session{FullSaveAssociations: true}).Updates(&user)
2. // ...
3. // INSERT INTO "addresses" (address1) VALUES ("Billing Address - Address 1"), ("Shipping Address - Address 1") ON DUPLICATE KEY SET address1=VALUES(address1);
4. // INSERT INTO "users" (name,billing_address_id,shipping_address_id) VALUES ("jinzhu", 1, 2);
5. // INSERT INTO "emails" (user_id,email) VALUES (111, "jinzhu@example.com"), (111, "jinzhu-2@example.com") ON DUPLICATE KEY SET email=VALUES(email);
6. // ...
Skip Auto Create/Update
To skip the auto save when creating/updating, you can use Select or Omit, for example:
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: "jinzhu@example.com"},
7. {Email: "jinzhu-2@example.com"},
8. },
9. Languages: []Language{
10. {Name: "ZH"},
11. {Name: "EN"},
12. },
13. }
15. db.Select("Name").Create(&user)
16. // INSERT INTO "users" (name) VALUES ("jinzhu", 1, 2);
18. db.Omit("BillingAddress").Create(&user)
19. // Skip create BillingAddress when creating a user
21. db.Omit(clause.Associations).Create(&user)
22. // Skip all associations when creating a user
NOTE: For many2many associations, GORM will upsert the associations before creating the join table references, if you want to skip the upserting of associations, you could skip it like:
1. db.Omit("Languages.*").Create(&user)The following code will skip the creation of the association and its references
1. db.Omit("Languages").Create(&user)
Select/Omit Association fields
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. }
7. // Create user and his BillingAddress, ShippingAddress
8. // When creating the BillingAddress only use its address1, address2 fields and omit others
9. db.Select("BillingAddress.Address1", "BillingAddress.Address2").Create(&user)
11. db.Omit("BillingAddress.Address2", "BillingAddress.CreatedAt").Create(&user)
Association Mode
Association Mode contains some commonly used helper methods to handle relationships
1. // Start Association Mode
2. var user User
3. db.Model(&user).Association("Languages")
4. // `user` is the source model, it must contains primary key
5. // `Languages` is a relationship's field name
6. // If the above two requirements matched, the AssociationMode should be started successfully, or it should return error
7. db.Model(&user).Association("Languages").Error
Find Associations
Find matched associations
1. db.Model(&user).Association("Languages").Find(&languages)
Find associations with conditions
1. codes := []string{"zh-CN", "en-US", "ja-JP"}
2. db.Model(&user).Where("code IN ?", codes).Association("Languages").Find(&languages)
4. db.Model(&user).Where("code IN ?", codes).Order("code desc").Association("Languages").Find(&languages)
Append Associations
Append new associations for many to many, has many, replace current association for has one, belongs to
1. db.Model(&user).Association("Languages").Append([]Language{languageZH, languageEN})
3. db.Model(&user).Association("Languages").Append(&Language{Name: "DE"})
5. db.Model(&user).Association("CreditCard").Append(&CreditCard{Number: "411111111111"})
Replace Associations
Replace current associations with new ones
1. db.Model(&user).Association("Languages").Replace([]Language{languageZH, languageEN})
3. db.Model(&user).Association("Languages").Replace(Language{Name: "DE"}, languageEN)
Delete Associations
Remove the relationship between source & arguments if exists, only delete the reference, won’t delete those objects from DB.
1. db.Model(&user).Association("Languages").Delete([]Language{languageZH, languageEN})
2. db.Model(&user).Association("Languages").Delete(languageZH, languageEN)
Clear Associations
Remove all reference between source & association, won’t delete those associations
1. db.Model(&user).Association("Languages").Clear()
Count Associations
Return the count of current associations
1. 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
Association Mode supports batch data, e.g:
1. // Find all roles for all users
2. db.Model(&users).Association("Role").Find(&roles)
4. // Delete User A from all user's team
5. db.Model(&users).Association("Team").Delete(&userA)
7. // Get distinct count of all users' teams
8. db.Model(&users).Association("Team").Count()
10. // For `Append`, `Replace` with batch data, the length of the arguments needs to be equal to the data's length or else it will return an error
11. var users = []User{user1, user2, user3}
12. // e.g: we have 3 users, Append userA to user1's team, append userB to user2's team, append userA, userB and userC to user3's team
13. db.Model(&users).Association("Team").Append(&userA, &userB, &[]User{userA, userB, userC})
14. // Reset user1's team to userA,reset user2's team to userB, reset user3's team to userA, userB and userC
15. db.Model(&users).Association("Team").Replace(&userA, &userB, &[]User{userA, userB, userC})
Delete with Select
You are allowed to delete selected has one/has many/many2many relations with Select when deleting records, for example:
1. // delete user's account when deleting user
2. db.Select("Account").Delete(&user)
4. // delete user's Orders, CreditCards relations when deleting user
5. db.Select("Orders", "CreditCards").Delete(&user)
7. // delete user's has one/many/many2many relations when deleting user
8. db.Select(clause.Associations).Delete(&user)
10. // delete each user's account when deleting users
11. db.Select("Account").Delete(&users)
NOTE: Associations will only be deleted if the deleting records’s primary key is not zero, GORM will use those primary keys as conditions to delete selected associations
1. // DOESN’T WORK 2. db.Select(“Account”).Where(“name = ?”, “jinzhu”).Delete(&User{}) 3. // will delete all user with name jinzhu, but those user’s account won’t be deleted
db.Select(“Account”).Where(“name = ?”, “jinzhu”).Delete(&User{ID: 1})
// will delete the user with name = jinzhu and id = 1, and user 1‘s account will be deleted
db.Select(“Account”).Delete(&User{ID: 1})
// will delete the user with id = 1, and user 1‘s account will be deleted
Association Tags
| Tag | Description |
|---|---|
| foreignKey | Specifies column name of the current model that is used as a foreign key to the join table |
| references | Specifies column name of the reference’s table that is mapped to the foreign key of the join table |
| polymorphic | Specifies polymorphic type such as model name |
| polymorphicValue | Specifies polymorphic value, default table name |
| many2many | Specifies join table name |
| joinForeignKey | Specifies foreign key column name of join table that maps to the current table |
| joinReferences | Specifies foreign key column name of join table that maps to the reference’s table |
| constraint | Relations constraint, e.g: OnUpdate,OnDelete |
