From df4a00a945aa2dfb1de210fafec6da4dc02a496d Mon Sep 17 00:00:00 2001 From: Jinzhu Date: Wed, 30 Jul 2014 22:50:27 +0800 Subject: [PATCH] Update README with Associations --- README.md | 109 ++++++++++++++++++++++++++++++++++++++------- callback_shared.go | 4 +- 2 files changed, 94 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index feec1290..fdb86396 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,7 @@ type User struct { ShippingAddress Address // Embedded struct (has one) ShippingAddressId int64 // Foreign key of ShippingAddress IgnoreMe int64 `sql:"-"` // Ignore this field + Languages []Language `gorm:"many2many:user_languages;"` // Many To Many, user_languages is the join table } type Email struct { @@ -80,6 +81,11 @@ type Address struct { Address2 string `sql:"type:varchar(100);unique"` Post sql.NullString `sql:not null` } + +type Language struct { + Id int64 + Name string +} ``` ## Initialize Database @@ -165,6 +171,7 @@ user := User{ BillingAddress: Address{Address1: "Billing Address - Address 1"}, ShippingAddress: Address{Address1: "Shipping Address - Address 1"}, Emails: []Email{{Email: "jinzhu@example.com"}, {Email: "jinzhu-2@example@example.com"}}, + Languages: []Language{{Name: "ZH"}, {Name: "EN"}}, } db.Create(&user) @@ -174,10 +181,14 @@ db.Create(&user) //// 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"); //// INSERT INTO "emails" (user_id,email) VALUES (111, "jinzhu-2@example.com"); +//// INSERT INTO "languages" ("name") VALUES ('ZH'); +//// INSERT INTO user_languages ("user_id","language_id") VALUES (111, 1); +//// INSERT INTO "languages" ("name") VALUES ('EN'); +//// INSERT INTO user_languages ("user_id","language_id") VALUES (111, 2); //// COMMIT; ``` -Refer [Query With Related](#query-with-related) for how to find associations +Refer [Associations](#associations) for how to works with associations ## Query @@ -301,21 +312,6 @@ db.Where("name = 'jinzhu'").Or(User{Name: "jinzhu 2"}).Find(&users) db.Where("name = 'jinzhu'").Or(map[string]interface{}{"name": "jinzhu 2"}).Find(&users) ``` -### Query With Related - -```go -// Find associations with guessed foreign key -db.Model(&user).Related(&emails) -//// SELECT * FROM emails WHERE user_id = 111; // 111 is user's Id - -db.Model(&email).Related(&user) -//// SELECT * FROM users WHERE id = 111; // 111 is email's UserId - -// Find associations with specified foreign key -db.Model(&user).Related(&address1, "BillingAddressId") -//// SELECT * FROM addresses WHERE id = 123; // 123 is user's BillingAddressId -``` - ### Query Chains Gorm has a chainable API, you could use it like this @@ -419,6 +415,87 @@ db.Unscoped().Delete(&order) // DELETE FROM orders WHERE id=10; ``` +## Associations + +### Has One + +```go +// User has one address +db.Model(&user).Related(&address) +//// SELECT * FROM addresses WHERE id = 123; // 123 is user's foreign key AddressId + +// Specify the foreign key +db.Model(&user).Related(&address1, "BillingAddressId") +//// SELECT * FROM addresses WHERE id = 123; // 123 is user's foreign key BillingAddressId +``` + +### Belongs To + +```go +// Email belongs to user +db.Model(&email).Related(&user) +//// SELECT * FROM users WHERE id = 111; // 111 is email's foreign key UserId + +// Specify the foreign key +db.Model(&email).Related(&user, "ProfileId") +//// SELECT * FROM users WHERE id = 111; // 111 is email's foreign key ProfileId +``` + +### Has Many + +```go +// User has many emails +db.Model(&user).Related(&emails) +//// SELECT * FROM emails WHERE user_id = 111; +// user_id is the foreign key, 111 is user's primary key's value + +// Specify the foreign key +db.Model(&user).Related(&emails, "ProfileId") +//// SELECT * FROM emails WHERE profile_id = 111; +// profile_id is the foreign key, 111 is user's primary key's value +``` + +### Many To Many + +```go +// User has many languages and belongs to many languages +db.Model(&user).Related(&languages, "Languages") +//// SELECT * FROM "languages" INNER JOIN "user_languages" ON "user_languages"."language_id" = "languages"."id" WHERE "user_languages"."user_id" = 111 +// `Languages` is user's column name, this column's tag defined join table like this `gorm:"many2many:user_languages;"` +``` + +There is also a mode used to handle many to many relations easily + +```go +// Query +db.Model(&user).Association("Languages").Find(&languages) +// same as `db.Model(&user).Related(&languages, "Languages")` + +db.Where("name = ?", "ZH").First(&languageZH) +db.Where("name = ?", "EN").First(&languageEN) + +// Append +db.Model(&user).Association("Languages").Append([]Language{languageZH, languageEN}) +db.Model(&user).Association("Languages").Append([]Language{{Name: "DE"}}) +db.Model(&user).Association("Languages").Append(Language{Name: "DE"}) + +// Delete +db.Model(&user).Association("Languages").Delete([]Language{languageZH, languageEN}) +db.Model(&user).Association("Languages").Delete(languageZH, languageEN) + +// Replace +db.Model(&user).Association("Languages").Replace([]Language{languageZH, languageEN}) +db.Model(&user).Association("Languages").Replace(Language{Name: "DE"}, languageEN) + +// Count +db.Model(&user).Association("Languages").Count() +// Return the count of languages the user has + +// Clear +db.Model(&user).Association("Languages").Clear() +// Remove all relations between the user and languages +``` + ## Advanced Usage ## FirstOrInit diff --git a/callback_shared.go b/callback_shared.go index dd9445c9..c0de840a 100644 --- a/callback_shared.go +++ b/callback_shared.go @@ -82,9 +82,7 @@ func SaveAfterAssociations(scope *Scope) { scope.Quote(associationForeignKey), newScope.AddToVars(associationForeignValue), )) - if _, err := scope.DB().Exec(newScope.Sql, newScope.SqlVars...); err != nil { - scope.Err(err) - } + scope.Err(scope.NewDB().Exec(newScope.Sql, newScope.SqlVars...).Error) } } default: