GORM 基础 -- Associations
1、Belongs To
属于(belongs to
)关联设置与另一个模型建立一对一的连接,这样声明模型的每个实例都“属于(belongs to)”另一个模型的一个实例。
例如,如果您的应用程序包括用户(users )和公司(companies),并且每个用户只能分配给一个公司,那么以下类型表示这种关系。注意这里,在User
对象上,有一个CompanyID
和一个Company
。默认情况下,CompanyID
被隐式用于在User
和Company
表之间创建外键关系,因此必须包含在User
结构体中以填充Company
内部结构。
// `User` belongs to `Company`, `CompanyID` is the foreign key
type User struct {gorm.ModelName stringCompanyID intCompany Company
}type Company struct {ID intName string
}
有关填充内部结构的详细信息,请参阅预先加载。
1.1 覆写外键
要定义一个属于关系,外键必须存在,默认外键使用所有者(owner’s )的类型名加上它的主字段名。
对于上面的例子,要定义属于Company
的User
模型,按照约定外键应该是CompanyID
GORM提供了一种自定义外键的方法,例如:
type User struct {gorm.ModelName stringCompanyRefer intCompany Company `gorm:"foreignKey:CompanyRefer"`// use CompanyRefer as foreign key
}type Company struct {ID intName string
}
1.2 覆写引用(References)
对于属于关系,GORM通常使用所有者的主键字段作为外键的值,对于上面的例子,它是Company
的字段ID
。
当您将用户分配给公司时,GORM将把公司ID
保存到用户的CompanyID
字段中。
你可以通过标签references
来改变它,例如:
type User struct {gorm.ModelName stringCompanyID stringCompany Company `gorm:"references:Code"` // use Code as references
}type Company struct {ID intCode stringName string
}
GORM通常猜测关系是
has one
,如果覆写外键名称已经存在于所有者类型中,我们需要在belongs to
关系中指定references
。
type User struct {gorm.ModelName stringCompanyID stringCompany Company `gorm:"references:CompanyID"` // use Company.CompanyID as references
}type Company struct {CompanyID intCode stringName string
}
1.3 CRUD with Belongs To
要使用 belongs to
关系的关联模式(Association Mode )
1.4 预先加载 (Eager Loading)
GORM允许使用Preload
和Joins
预先加载属belongs to
关联,请参阅预先加载(即时加载)了解详细信息
1.5 外键约束
你可以用标签constraint
设置OnUpdate
, OnDelete
约束,它将创建与GORM
迁移时,例如:
type User struct {gorm.ModelName stringCompanyID intCompany Company `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
}type Company struct {ID intName string
}
2、Has One
has one
关联,与另一个模型建立一对一的连接,但是语义(和结果)略有不同。这种关联表明一个模型的每个实例包含或拥有另一个模型的一个实例。
例如,如果您的应用程序包括用户和信用卡,并且每个用户只能拥有一张信用卡。
2.1 声明
// User has one CreditCard, UserID is the foreign key
type User struct {gorm.ModelCreditCard CreditCard
}type CreditCard struct {gorm.ModelNumber stringUserID uint
}
2.2 检索
// Retrieve user list with eager loading credit card
func GetAll(db *gorm.DB) ([]User, error) {var users []Usererr := db.Model(&User{}).Preload("CreditCard").Find(&users).Errorreturn users, err
}
2.3 覆盖外键
对于has one
关系,外键字段必须也存在,所有者将属于它的模型的主键保存到这个字段中。
字段的名称通常是由has one
模型的类型加上它的主键生成的,对于上面的例子来说,它是UserID
。
当您向用户提供信用卡时,它会将用户的ID
保存到UserID
字段中。
如果你想用另一个字段来保存关系,你可以用标签foreignKey
来改变它,例如:
type User struct {gorm.ModelCreditCard CreditCard `gorm:"foreignKey:UserName"`// use UserName as foreign key
}type CreditCard struct {gorm.ModelNumber stringUserName string
}
2.4 覆盖引用
默认情况下,拥有的实体将拥有has one
模型的主键保存为外键,您可以更改为保存另一个字段的值,例如下面的示例使用Name
。
你可以通过标签references
来改变它,例如:
type User struct {gorm.ModelName string `gorm:"index"`CreditCard CreditCard `gorm:"foreignKey:UserName;references:name"`
}type CreditCard struct {gorm.ModelNumber stringUserName string
}
2.5 多态性关联
GORM对于has one
和has many
支持多态关联,它将拥有实体的表名保存到多态类型的字段中,主键保存到多态字段中
type Cat struct {ID intName stringToy Toy `gorm:"polymorphic:Owner;"`
}type Dog struct {ID intName stringToy Toy `gorm:"polymorphic:Owner;"`
}type Toy struct {ID intName stringOwnerID intOwnerType string
}db.Create(&Dog{Name: "dog1", Toy: Toy{Name: "toy1"}})
// INSERT INTO `dogs` (`name`) VALUES ("dog1")
// INSERT INTO `toys` (`name`,`owner_id`,`owner_type`) VALUES ("toy1","1","dogs")
你可以用标签polymorphicValue
改变多态类型的值,例如:
type Dog struct {ID intName stringToy Toy `gorm:"polymorphic:Owner;polymorphicValue:master"`
}type Toy struct {ID intName stringOwnerID intOwnerType string
}db.Create(&Dog{Name: "dog1", Toy: Toy{Name: "toy1"}})
// INSERT INTO `dogs` (`name`) VALUES ("dog1")
// INSERT INTO `toys` (`name`,`owner_id`,`owner_type`) VALUES ("toy1","1","master")
2.6 CRUD with Has One
请参考关联模型的has one
2.7 预加载
GORM允许使用Preload
和Joins
为has one
关联预加载,请参阅预加载(即时加载)了解详细信息
Self-Referential Has One
type User struct {gorm.ModelName stringManagerID *uintManager *User
}
2.8 外键约束
你可以用标签constraint
设置OnUpdate
, OnDelete
约束,当GORM迁移时它将创建,例如:
type User struct {gorm.ModelCreditCard CreditCard `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
}type CreditCard struct {gorm.ModelNumber stringUserID uint
}
您还可以删除用Select
选中的has one
关联, Delete with Select的详细信息
3、Has Many
3.1 Has Many
has many
关联,与另一个模型建立一对多(one-to-many)的连接,与拥有has one
模型不同,所有者可以拥有0个或多个模型实例。
例如,如果您的应用程序包括用户和信用卡,并且每个用户可以有许多信用卡。
3.2 Declare
// User has many CreditCards, UserID is the foreign key
type User struct {gorm.ModelCreditCards []CreditCard
}type CreditCard struct {gorm.ModelNumber stringUserID uint
}
3.3 检索
// Retrieve user list with eager loading credit cards
func GetAll(db *gorm.DB) ([]User, error) {var users []Usererr := db.Model(&User{}).Preload("CreditCards").Find(&users).Errorreturn users, err
}
3.4 覆盖外键
要定义一个has many
关系,外键必须存在。默认外键的名称是所有者的类型名称加上其主键字段的名称
例如,要定义一个属于User
的模型,外键应该是UserID
。
使用其他字段作为外键,你可以自定义一个foreignKey
标签,例如:
type User struct {gorm.ModelCreditCards []CreditCard `gorm:"foreignKey:UserRefer"`
}type CreditCard struct {gorm.ModelNumber stringUserRefer uint
}
3.5 覆盖引用
GORM通常使用所有者的主键作为外键的值,对于上面的例子,它是User
的ID
,
当您将信用卡分配给用户时,GORM将把用户的ID
保存到信用卡的UserID
字段中。
你可以通过标签references
来改变它,例如:
type User struct {gorm.ModelMemberNumber stringCreditCards []CreditCard `gorm:"foreignKey:UserNumber;references:MemberNumber"`
}type CreditCard struct {gorm.ModelNumber stringUserNumber string
}
3.6 多态关联
GORM支持多态关联,将拥有实体的表名保存到多态类型(type)的字段中,主键值保存到多态字段中
type Dog struct {ID intName stringToys []Toy `gorm:"polymorphic:Owner;"`
}type Toy struct {ID intName stringOwnerID intOwnerType string
}db.Create(&Dog{Name: "dog1", Toys: []Toy{{Name: "toy1"}, {Name: "toy2"}}})
// INSERT INTO `dogs` (`name`) VALUES ("dog1")
// INSERT INTO `toys` (`name`,`owner_id`,`owner_type`) VALUES ("toy1","1","dogs"), ("toy2","1","dogs")
你可以用标签polymorphicValue
改变多态类型的值,例如:
type Dog struct {ID intName stringToys []Toy `gorm:"polymorphic:Owner;polymorphicValue:master"`
}type Toy struct {ID intName stringOwnerID intOwnerType string
}db.Create(&Dog{Name: "dog1", Toys: []Toy{{Name: "toy1"}, {Name: "toy2"}}})
// INSERT INTO `dogs` (`name`) VALUES ("dog1")
// INSERT INTO `toys` (`name`,`owner_id`,`owner_type`) VALUES ("toy1","1","master"), ("toy2","1","master")
3.7 CRUD with Has Many
请参考关联模型的has many
3.8 预加载
GORM允许使用Preload
为has many
关联预加载,请参阅预加载(快速加载)了解详细信息
Self-Referential Has Many
type User struct {gorm.ModelName stringManagerID *uintTeam []User `gorm:"foreignkey:ManagerID"`
}
3.9 外键约束
你可以用不用标签constraint
设置OnUpdate
, OnDelete
约束,在GORM迁移时它将创建,例如:
type User struct {gorm.ModelCreditCards []CreditCard `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
}type CreditCard struct {gorm.ModelNumber stringUserID uint
}
您还可以删除用Select
选中的has many
关联, Delete with Select的详细信息
4、Many To Many
多对多在两个模型之间添加一个连接表。
例如,如果您的应用程序包括用户和语言,一个用户可以说多种语言,而许多用户可以说一种指定的语言。
// User has and belongs to many languages, `user_languages` is the join table
type User struct {gorm.ModelLanguages []Language `gorm:"many2many:user_languages;"`
}type Language struct {gorm.ModelName string
}
当使用GORM AutoMigrate
为User
创建表时,GORM将自动创建连接表
4.1 Back-Reference
Declare
// User has and belongs to many languages, use `user_languages` as join table
type User struct {gorm.ModelLanguages []*Language `gorm:"many2many:user_languages;"`
}type Language struct {gorm.ModelName stringUsers []*User `gorm:"many2many:user_languages;"`
}
检索
// Retrieve user list with eager loading languages
func GetAllUsers(db *gorm.DB) ([]User, error) {var users []Usererr := db.Model(&User{}).Preload("Languages").Find(&users).Errorreturn users, err
}// Retrieve language list with eager loading users
func GetAllLanguages(db *gorm.DB) ([]Language, error) {var languages []Languageerr := db.Model(&Language{}).Preload("Users").Find(&languages).Errorreturn languages, err
}
4.2 覆盖外键
对于多对多关系,连接表拥有引用两个模型的外键,例如:
type User struct {gorm.ModelLanguages []Language `gorm:"many2many:user_languages;"`
}type Language struct {gorm.ModelName string
}// Join Table: user_languages
// foreign key: user_id, reference: users.id
// foreign key: language_id, reference: languages.id
要覆盖它们,你可以使用标签foreignKey
, references
, joinForeignKey
, joinReferences
,没有必要一起使用,你可以只使用其中一个来覆盖一些外键/引用
type User struct {gorm.ModelProfiles []Profile `gorm:"many2many:user_profiles;foreignKey:Refer;joinForeignKey:UserReferID;References:UserRefer;joinReferences:ProfileRefer"`Refer uint `gorm:"index:,unique"`
}type Profile struct {gorm.ModelName stringUserRefer uint `gorm:"index:,unique"`
}// Which creates join table: user_profiles
// foreign key: user_refer_id, reference: users.refer
// foreign key: profile_refer, reference: profiles.user_refer
注意:
有些数据库只允许创建引用具有唯一索引的字段的数据库外键,因此如果在迁移时创建数据库外键,则需要指定unique index
标记
4.3 Self-Referential Many2Many
type User struct {gorm.ModelFriends []*User `gorm:"many2many:user_friends"`
}// Which creates join table: user_friends
// foreign key: user_id, reference: users.id
// foreign key: friend_id, reference: users.id
4.4 Eager Loading
GORM允许使用Preload
为many2many
关联预加载,请参阅预加载(快速加载)了解详细信息
4.5 CRUD with Many2Many
请参考关联模型的has many
4.6 自定义 JoinTable
JoinTable
可以是一个功能齐全的模型,比如有软删除(Soft Delete
),钩子(Hooks
)支持和更多的字段,你可以用SetupJoinTable
来设置它,例如:
注意:
自定义连接表的外键必须是组合主键或组合唯一索引
type Person struct {ID intName stringAddresses []Address `gorm:"many2many:person_address;"`
}type Address struct {ID uintName string
}type PersonAddress struct {PersonID int `gorm:"primaryKey"`AddressID int `gorm:"primaryKey"`CreatedAt time.TimeDeletedAt gorm.DeletedAt
}func (PersonAddress) BeforeCreate(db *gorm.DB) error {// ...
}// Change model Person's field Addresses' join table to PersonAddress
// PersonAddress must defined all required foreign keys or it will raise error
err := db.SetupJoinTable(&Person{}, "Addresses", &PersonAddress{})
4.7 外键约束
你可以使用标签constraint
设置OnUpdate
, OnDelete
约束,在GORM迁移时它将创建,例如:
type User struct {gorm.ModelLanguages []Language `gorm:"many2many:user_speaks;"`
}type Language struct {Code string `gorm:"primarykey"`Name string
}// CREATE TABLE `user_speaks` (`user_id` integer,`language_code` text,PRIMARY KEY (`user_id`,`language_code`),CONSTRAINT `fk_user_speaks_user` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE SET NULL ON UPDATE CASCADE,CONSTRAINT `fk_user_speaks_language` FOREIGN KEY (`language_code`) REFERENCES `languages`(`code`) ON DELETE SET NULL ON UPDATE CASCADE);
您还可以删除用Select
选中的many2many
关联, Delete with Select的详细信息
4.8 复合外键
如果您的模型使用复合主键,GORM将默认启用复合外键
你可以重写默认的外键,指定多个外键,只是用逗号分隔这些键的名称,例如:
你可以重写默认的外键,指定多个外键,只是用逗号分隔这些键的名称,例如:
type Tag struct {ID uint `gorm:"primaryKey"`Locale string `gorm:"primaryKey"`Value string
}type Blog struct {ID uint `gorm:"primaryKey"`Locale string `gorm:"primaryKey"`Subject stringBody stringTags []Tag `gorm:"many2many:blog_tags;"`LocaleTags []Tag `gorm:"many2many:locale_blog_tags;ForeignKey:id,locale;References:id"`SharedTags []Tag `gorm:"many2many:shared_blog_tags;ForeignKey:id;References:id"`
}// Join Table: blog_tags
// foreign key: blog_id, reference: blogs.id
// foreign key: blog_locale, reference: blogs.locale
// foreign key: tag_id, reference: tags.id
// foreign key: tag_locale, reference: tags.locale// Join Table: locale_blog_tags
// foreign key: blog_id, reference: blogs.id
// foreign key: blog_locale, reference: blogs.locale
// foreign key: tag_id, reference: tags.id// Join Table: shared_blog_tags
// foreign key: blog_id, reference: blogs.id
// foreign key: tag_id, reference: tags.id
5、关联模型
5.1 自动创建/更新
在创建/更新记录时,GORM将使用Upsert
自动保存关联及其引用。
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"},},
}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
模式:
db.Session(&gorm.Session{FullSaveAssociations: true}).Updates(&user)
// ...
// INSERT INTO "addresses" (address1) VALUES ("Billing Address - Address 1"), ("Shipping Address - Address 1") ON DUPLICATE KEY SET address1=VALUES(address1);
// 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 SET email=VALUES(email);
// ...
5.2 跳过自动创建/更新
要在创建/更新时跳过自动保存,你可以使用Select
或Omit
,例如:
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"},},
}db.Select("Name").Create(&user)
// INSERT INTO "users" (name) VALUES ("jinzhu", 1, 2);db.Omit("BillingAddress").Create(&user)
// Skip create BillingAddress when creating a userdb.Omit(clause.Associations).Create(&user)
// Skip all associations when creating a user
注意:
对于many2many
关联,GORM会在创建连接表引用之前插入关联,如果你想跳过关联的插入,你可以像这样跳过:
db.Omit("Languages.*").Create(&user)
下面的代码将跳过关联及其引用的创建
db.Omit("Languages").Create(&user)
5.3 选择/省略(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
// When creating the BillingAddress only use its address1, address2 fields and omit others
db.Select("BillingAddress.Address1", "BillingAddress.Address2").Create(&user)db.Omit("BillingAddress.Address2", "BillingAddress.CreatedAt").Create(&user)
5.4 关联模式
关联模式包含一些常用的帮助器方法来处理关系
// Start Association Mode
var user User
db.Model(&user).Association("Languages")
// `user` is the source model, it must contains primary key
// `Languages` is a relationship's field name
// If the above two requirements matched, the AssociationMode should be started successfully, or it should return error
db.Model(&user).Association("Languages").Error
5.4.1 查找关联
匹配的关联
db.Model(&user).Association("Languages").Find(&languages)
有条件查找关联
codes := []string{"zh-CN", "en-US", "ja-JP"}
db.Model(&user).Where("code IN ?", codes).Association("Languages").Find(&languages)db.Model(&user).Where("code IN ?", codes).Order("code desc").Association("Languages").Find(&languages)
5.4.2 Append 关联
为many to many
,has many
附加新关联,为has one
,belongs to
替换现有关联
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"})
5.4.3 Replace 关联
用新的关联替换当前的关联
db.Model(&user).Association("Languages").Replace([]Language{languageZH, languageEN})db.Model(&user).Association("Languages").Replace(Language{Name: "DE"}, languageEN)
5.4.4 Delete 关联
如果存在,删除源和参数之间的关系,只删除引用,不会从DB中删除这些对象。
db.Model(&user).Association("Languages").Delete([]Language{languageZH, languageEN})
db.Model(&user).Association("Languages").Delete(languageZH, languageEN)
5.4.5 Clear 关联
删除源和关联之间的所有引用,不会删除这些关联
db.Model(&user).Association("Languages").Clear()
5.4.6 Count 关联
返回当前关联的计数
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()
5.4.7 Batch Data
关联模式支持批量数据,例如:
// Find all roles for all users
db.Model(&users).Association("Role").Find(&roles)// Delete User A from all user's team
db.Model(&users).Association("Team").Delete(&userA)// Get distinct count of all users' teams
db.Model(&users).Association("Team").Count()// 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
var users = []User{user1, user2, user3}
// 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
db.Model(&users).Association("Team").Append(&userA, &userB, &[]User{userA, userB, userC})
// Reset user1's team to userA,reset user2's team to userB, reset user3's team to userA, userB and userC
db.Model(&users).Association("Team").Replace(&userA, &userB, &[]User{userA, userB, userC})
5.5 Delete with Select
在删除记录时,可以使用Select
删除选中的有has one/has many/many2many
关系。例如:
// delete user's account when deleting user
db.Select("Account").Delete(&user)// delete user's Orders, CreditCards relations when deleting user
db.Select("Orders", "CreditCards").Delete(&user)// delete user's has one/many/many2many relations when deleting user
db.Select(clause.Associations).Delete(&user)// delete each user's account when deleting users
db.Select("Account").Delete(&users)
注意:
只有当删除记录的主键不为零时,关联才会被删除,GORM将使用这些主键作为删除所选关联的条件
// DOESN'T WORK
db.Select("Account").Where("name = ?", "jinzhu").Delete(&User{})
// will delete all user with name `jinzhu`, but those user's account won't be deleteddb.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 deleteddb.Select("Account").Delete(&User{ID: 1})
// will delete the user with id = `1`, and user `1`'s account will be deleted
5.6 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 |
6、Preloading (Eager Loading)
6.1 Preload
GORM允许在其他SQL中使用Preload
快速加载关联,例如:
type User struct {gorm.ModelUsername stringOrders []Order
}type Order struct {gorm.ModelUserID uintPrice float64
}// Preload Orders when find users
db.Preload("Orders").Find(&users)
// SELECT * FROM users;
// SELECT * FROM orders WHERE user_id IN (1,2,3,4);db.Preload("Orders").Preload("Profile").Preload("Role").Find(&users)
// SELECT * FROM users;
// SELECT * FROM orders WHERE user_id IN (1,2,3,4); // has many
// SELECT * FROM profiles WHERE user_id IN (1,2,3,4); // has one
// SELECT * FROM roles WHERE id IN (4,5,6); // belongs to
6.2 Joins Preloading
Preload
在一个单独的查询中加载关联数据,Join Preload
将使用内部连接加载关联数据,例如:
db.Joins("Company").Joins("Manager").Joins("Account").First(&user, 1)
db.Joins("Company").Joins("Manager").Joins("Account").First(&user, "users.name = ?", "jinzhu")
db.Joins("Company").Joins("Manager").Joins("Account").Find(&users, "users.id IN ?", []int{1,2,3,4,5})
Join with conditions
db.Joins("Company", DB.Where(&Company{Alive: true})).Find(&users)
// SELECT `users`.`id`,`users`.`name`,`users`.`age`,`Company`.`id` AS `Company__id`,`Company`.`name` AS `Company__name` FROM `users` LEFT JOIN `companies` AS `Company` ON `users`.`company_id` = `Company`.`id` AND `Company`.`alive` = true;
Join Preload
工作在一对一的关系下,例如:has one
,belong to
6.3 Preload All
当创建/更新时,clause.Associations
可以和Preload
一起使用类似于Select
,你可以使用它来Preload
所有的关联,例如:
type User struct {gorm.ModelName stringCompanyID uintCompany CompanyRole RoleOrders []Order
}db.Preload(clause.Associations).Find(&users)
clause.Associations
won’t preload nested associations, but you can use it with Nested Preloading together, e.g:
db.Preload("Orders.OrderItems.Product").Preload(clause.Associations).Find(&users)
6.4 Preload with conditions
GORM允许有条件地预加载关联,它的工作原理类似于内联条件
// Preload Orders with conditions
db.Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users)
// SELECT * FROM users;
// SELECT * FROM orders WHERE user_id IN (1,2,3,4) AND state NOT IN ('cancelled');db.Where("state = ?", "active").Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users)
// SELECT * FROM users WHERE state = 'active';
// SELECT * FROM orders WHERE user_id IN (1,2) AND state NOT IN ('cancelled');
6.5 Custom Preloading SQL
You are able to custom preloading SQL by passing in func(db *gorm.DB) *gorm.DB
, for example:
db.Preload("Orders", func(db *gorm.DB) *gorm.DB {return db.Order("orders.amount DESC")
}).Find(&users)
// SELECT * FROM users;
// SELECT * FROM orders WHERE user_id IN (1,2,3,4) order by orders.amount DESC;
6.6 Nested Preloading
GORM supports nested preloading, for example:
db.Preload("Orders.OrderItems.Product").Preload("CreditCard").Find(&users)// Customize Preload conditions for `Orders`
// And GORM won't preload unmatched order's OrderItems then
db.Preload("Orders", "state = ?", "paid").Preload("Orders.OrderItems").Find(&users)
GORM 基础 -- Associations相关推荐
- Golang学习笔记之GORM基础使用(二)
本文章主要学习GORM的增删查改.若还没有完成数据库和数据表的创建.定义模型以及数据库的连接请先学习本本专栏文章Golang学习笔记之GORM基础使用(一).本文为学习笔记,通过GORM官方中文文档和 ...
- Golang学习笔记之GORM基础使用(一)
本文章主要学习了GORM的基础知识,数据库的连接以及数据库表的建立的多种方法.本文为学习笔记,通过GORM官方中文文档和李文周的博客学习整理而成. gorm是一个使用Go语言编写的ORM框架.它文档齐 ...
- GORM 基础 -- Gen
https://gorm.io/gen/ github 1.GEN Guides GEN:友好和更安全的代码生成 1.1 概述 来自动态原始SQL的惯用和可重用API 100%类型安全的DAO API ...
- 从数据结构及汇编角度深入学习go语言
原文连接 Golang基础知识 源码调试 从汇编角度理解go go/c/c++常用功能对应的汇编指令 数据结构 内建容器简介 array/slice map 字符串 结构体 接口 常用关键字 for和 ...
- grails学习笔记
配置篇 在config.groovy文件中有名为layer1.prop1的参数.请问,在Controller中如何访问它?在Service中呢? 访问方式一样,可采用以下任意一种方法: view so ...
- Gorm学习(四)基础:关联
目录 前言 一.One To One 一对一 1.Belongs To 属于 1)创建记录 2)查询记录 3)重写外键 4)重写引用 5)关联模式 a.查找关联 b.删除关联 c.添加关联 d.修改( ...
- go语言gorm实战——基础技术总结
前言: 一个go项目过后,有许多的精华部分.容易违犯go语言常规的部分,总结.记录,以供后续的学习.参考和大家探讨. 1 CRUD 1.1 单个查询.批量查询 // leimin // 查询指定ID主 ...
- MySQL基础及GORM框架
SQL概念 什么是SQL 即Structured Query Language结构化查询语言,访问和处理关系型数据库的计算机语言 为什么需要数据库 程序运行时使用到的数据通常保存在内存中,一旦关闭就消 ...
- Go语言教程第十六集 GORM详解
GORM介绍和使用 什么是ORM Object Relational Mapping:对象关系映射 结构体 和 SQL数据库存在映射,这个时候就有了ORM语句 一句话说:就是将数据库中的表数据 和 结 ...
最新文章
- 2019.08.04 新建随笔
- boost::shared_ptr用法测试程序
- ios配置pch文件及使用
- matlab求被21整除,用matlab求[100,999]之间能被21整除的数的个数,还有建立一个字符串向量,删除大写字母._...
- 分布式系统原理 之6 两阶段提交协议
- synchronized原理_synchronized 关键字底层原理
- 北大青鸟java y2_Struts-2 北大青鸟 Y2学年 项目案例使用 2框架开发租房网站 Java Develop 249万源代码下载- www.pudn.com...
- cad 打开硬件加速卡_CAD卡顿?电脑带不动?几个简单实用的方法,解决CAD运行卡顿问题...
- AudioBufferSourceNode
- nopcommerce 开源商城
- C#----接口的显式实现
- CH32F103C8T6核心板三种程序下载方式简介
- luogu p4556 [Vani有约会]雨天的尾巴 树上差分,最近公共祖先,线段树合并
- C++中++cnt1[s1[i]-‘a‘]的意思
- MATLAB--读取广播星历的导航文件
- scheme语言编译成c语言,Scheme语言--简单介绍
- rm安全删除(一条命令变rm为mv)
- 虚拟机主机服务器出现SSH已启用,ESXi去掉 SSH已经启用的警告信息
- ios 微信分享重新编码链接_iOS微信分享及从Safari跳转到App
- 什么是代码,源文件、编辑和编译?
热门文章
- 电机调速制动matlab,鼠笼式三相异步电机:起动、调速、制动(原理与Simulink仿真)...
- Milvus 2.0 Knowhere 概览
- 机器人企业如何在激流勇进的市场中,深耕落地,突出重围?
- ACR Loss: Adaptive Coordinate-based Regression Loss for Face Alignment
- VMware虚拟机克隆后解决网络冲突问题
- 跳槽关系三国演义告诉我们的60条真理
- (附源码)基于springboot在线考试报名系统 毕业设计031706
- 360和QQ,拿什么来拯救你?
- NBA总决赛。。。。
- 致同:三年行动任务过半 国企改革务实发展