目录

一 Belongs To(一对一)

1.1 Belongs To

belongs to 会与另一个模型建立了一对一的连接。 这种模型的每一个实例都“属于”另一个模型的一个实例。

例如,您的应用包含 user 和 company,并且每个 user 能且只能被分配给一个 company。下面的类型就表示这种关系。 注意,在 User 对象中,有一个和 Company 一样的 CompanyID。 默认情况下, CompanyID 被隐含地用来在 UserCompany 之间创建一个外键关系, 因此必须包含在 User 结构体中才能填充 Company 内部结构体。

// `User` 属于 `Company`,`CompanyID` 是外键
type User struct {
gorm.Model
Name string
CompanyID int
Company Company
} type Company struct {
ID int
Name string
} db.AutoMigrate(&User{},&Company{})

请参阅 预加载 以了解内部结构的详细信息。

1.2 重写外键

要定义一个 belongs to 关系,数据库的表中必须存在外键。默认情况下,外键的名字,使用拥有者的类型名称加上表的主键的字段名字

例如,定义一个User实体属于Company实体,那么外键的名字一般使用CompanyID。

GORM同时提供自定义外键名字的方式,如下例所示。

type User struct {
gorm.Model
Name string
CompanyRefer int // 外键改名字为CompanyRefer
Company Company `gorm:"foreignKey:CompanyRefer"`
// 使用 CompanyRefer 作为外键
} type Company struct {
ID int
Name string
}

1.3 重写引用(一般不用)

对于 belongs to 关系,GORM 通常使用数据库表,主表(拥有者)的主键值作为外键参考。 正如上面的例子,我们使用主表Company中的主键字段ID作为外键的参考值。

如果在Company实体中设置了User实体,那么GORM会自动把Company中的ID属性保存到User的CompanyID属性中。

同样的,您也可以使用标签 references 来更改它,例如:

type User struct {
gorm.Model
Name string
CompanyCode int
Company Company `gorm:"foreignKey:CompanyCode;references:Code"` // 指定外键字段为CompanyCode,指定与公司表中Code字段关联
} type Company struct {
ID int
Code int `gorm:"primarykey"`
Name string
}

1.4 Belongs to 的 CRUD

点击 关联模式 链接获取 belongs to 相关的用法

1.5 预加载

GORM允许通过使用Preload或者Joins来主动加载实体的关联关系,具体内容请参考,预加载(主动加载)

1.6 外键约束

你可以通过OnUpdate, OnDelete配置标签来增加关联关系的级联操作,如下面的例子,通过GORM可以完成用户和公司的级联更新和级联删除操作:

type User struct {
gorm.Model
Name string
Age int
UserDetailID int
UserDetail UserDetail `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"` // 级联更新,删除时置空
} type UserDetail struct {
ID int
Addr string
} // Navicat的设计表中可以查看

二、Has One

2.1 Has One

has one 与另一个模型建立一对一的关联,但它和一对一关系有些许不同。 这种关联表明一个模型的每个实例都包含或拥有另一个模型的一个实例。

例如,您的应用包含 user 和 credit card 模型,且每个 user 只能有一张 credit card。

// User 有一张 CreditCard,UserID 是外键
type User struct {
gorm.Model
CreditCard CreditCard // 与CreditCard表有关联关系
} type CreditCard struct {
gorm.Model
Number string
UserID uint //关联字段在此表
}

2.2 重写外键

对于 has one 关系,同样必须存在外键字段。拥有者将把属于它的模型的主键保存到这个字段。

这个字段的名称通常由 has one 模型的类型加上其 主键 生成,对于上面的例子,它是 UserID

为 user 添加 credit card 时,它会将 user 的 ID 保存到自己的 UserID 字段。

如果你想要使用另一个字段来保存该关系,你同样可以使用标签 foreignKey 来更改它,例如:

type User struct {
gorm.Model
CreditCard CreditCard `gorm:"foreignKey:UserName"`
// 使用 UserName 作为外键
} type CreditCard struct {
gorm.Model
Number string
UserName string // 使用 UserName 作为外键
}

2.3 重写引用

默认情况下,拥有者实体会将 has one 对应模型的主键保存为外键,您也可以修改它,用另一个字段来保存,例如下个这个使用 Name 来保存的例子。

您可以使用标签 references 来更改它,例如:

type User struct {
gorm.Model
Name int `gorm:"index"` // name建是索引
CreditCard CreditCard `gorm:"foreignkey:UserName;references:name"` // 信用卡表的UserName字段跟用户表Name字段关联
} type CreditCard struct {
gorm.Model
Number string
UserName int
}

2.4 多态关联

GORM 为 has onehas many 提供了多态关联支持,它会将拥有者实体的表名、主键值都保存到多态类型的字段中。

type Cat struct {
ID int
Name string
Toy Toy `gorm:"polymorphic:Owner;"`
} type Dog struct {
ID int
Name string
Toy Toy `gorm:"polymorphic:Owner;"`
} type Toy struct {
ID int
Name string
OwnerID int
OwnerType 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 int
Name string
Toy Toy `gorm:"polymorphic:Owner;polymorphicValue:master"`
} type Toy struct {
ID int
Name string
OwnerID int
OwnerType 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.5 Has One 的 CURD

查看 关联模式 获取 has one 相关的用法

2.6 预加载

GORM 可以通过 PreloadJoins 预加载 has one 关联的记录,查看 预加载 获取详情

2.7 自引用 Has One

type User struct {
gorm.Model
Name string
ManagerID *uint
Manager *User
}

2.8 外键约束

你可以通过为标签 constraint 配置 OnUpdateOnDelete 实现外键约束,在使用 GORM 进行迁移时它会被创建,例如:

type User struct {
gorm.Model
CreditCard CreditCard `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
} type CreditCard struct {
gorm.Model
Number string
UserID uint
}

你也可以在删除记录时通过 Select 来删除关联的记录,查看 Delete with Select 获取详情

三、Has Many

3.1 Has Many

has many 与另一个模型建立了一对多的连接。 不同于 has one,拥有者可以有零或多个关联模型。

例如,您的应用包含 user 和 credit card 模型,且每个 user 可以有多张 credit card。

// User 有多张 CreditCard,UserID 是外键
type User struct {
gorm.Model
CreditCards []CreditCard
} type CreditCard struct {
gorm.Model
Number string
UserID uint
}

3.2 重写外键

要定义 has many 关系,同样必须存在外键。 默认的外键名是拥有者的类型名加上其主键字段名

例如,要定义一个属于 User 的模型,则其外键应该是 UserID

此外,想要使用另一个字段作为外键,您可以使用 foreignKey 标签自定义它:

type User struct {
gorm.Model
CreditCards []CreditCard `gorm:"foreignKey:UserRefer"`
} type CreditCard struct {
gorm.Model
Number string
UserRefer uint
}

3.3 重写引用

GORM 通常使用拥有者的主键作为外键的值。 对于上面的例子,它是 UserID 字段。

为 user 添加 credit card 时,GORM 会将 user 的 ID 字段保存到 credit card 的 UserID 字段。

同样的,您也可以使用标签 references 来更改它,例如:

type User struct {
gorm.Model
MemberNumber string
CreditCards []CreditCard `gorm:"foreignKey:UserNumber;references:MemberNumber"`
} type CreditCard struct {
gorm.Model
Number string
UserNumber string
}

3.4 多态关联

GORM 为 has onehas many 提供了多态关联支持,它会将拥有者实体的表名、主键都保存到多态类型的字段中。

type Dog struct {
ID int
Name string
Toys []Toy `gorm:"polymorphic:Owner;"`
} type Toy struct {
ID int
Name string
OwnerID int
OwnerType 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 int
Name string
Toys []Toy `gorm:"polymorphic:Owner;polymorphicValue:master"`
} type Toy struct {
ID int
Name string
OwnerID int
OwnerType 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.5 Has Many 的 CURD

查看 关联模式 获取 has many 相关的用法

3.6 预加载

GORM 可以通过 Preload 预加载 has many 关联的记录,查看 预加载 获取详情

3.7自引用 Has Many

type User struct {
gorm.Model
Name string
ManagerID *uint
Team []User `gorm:"foreignkey:ManagerID"`
}

3.8 外键约束

你可以通过为标签 constraint 配置 OnUpdateOnDelete 实现外键约束,在使用 GORM 进行迁移时它会被创建,例如:

type User struct {
gorm.Model
CreditCards []CreditCard `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
} type CreditCard struct {
gorm.Model
Number string
UserID uint
}

你也可以在删除记录时通过 Select 来删除 has many 关联的记录,查看 Delete with Select 获取详情

四、Many To Many(多对多)

4.1 Many To Many

Many to Many 会在两个 model 中添加一张连接表。

例如,您的应用包含了 user 和 language,且一个 user 可以说多种 language,多个 user 也可以说一种 language。

// User 拥有并属于多种 language,`user_languages` 是连接表
type User struct {
gorm.Model
Languages []Language `gorm:"many2many:user_languages;"`
} type Language struct {
gorm.Model
Name string
}

当使用 GORM 的 AutoMigrateUser 创建表时,GORM 会自动创建连接表

4.2 反向引用

// User 拥有并属于多种 language,`user_languages` 是连接表
type User struct {
gorm.Model
Languages []*Language `gorm:"many2many:user_languages;"`
} type Language struct {
gorm.Model
Name string
Users []*User `gorm:"many2many:user_languages;"`
}

4.3 重写外键

对于 many2many 关系,连接表会同时拥有两个模型的外键,例如:

type User struct {
gorm.Model
Languages []Language `gorm:"many2many:user_languages;"`
} type Language struct {
gorm.Model
Name string
} // 连接表:user_languages
// foreign key: user_id, reference: users.id
// foreign key: language_id, reference: languages.id

若要重写它们,可以使用标签 foreignKeyreferencesjoinforeignKeyjoinReferences。当然,您不需要使用全部的标签,你可以仅使用其中的一个重写部分的外键、引用。

type User struct {
gorm.Model
Profiles []Profile `gorm:"many2many:user_profiles;foreignKey:Refer;joinForeignKey:UserReferID;References:UserRefer;joinReferences:ProfileRefer"`
Refer uint `gorm:"index:,unique"`
} type Profile struct {
gorm.Model
Name string
UserRefer uint `gorm:"index:,unique"`
} // 会创建连接表:user_profiles
// foreign key: user_refer_id, reference: users.refer
// foreign key: profile_refer, reference: profiles.user_refer

注意: 某些数据库只允许在唯一索引字段上创建外键,如果您在迁移时会创建外键,则需要指定 unique index 标签。

4.4 自引用 Many2Many

自引用 many2many 关系

type User struct {
gorm.Model
Friends []*User `gorm:"many2many:user_friends"`
} // 会创建连接表:user_friends
// foreign key: user_id, reference: users.id
// foreign key: friend_id, reference: users.id

4.5 预加载

GORM 可以通过 Preload 预加载 has many 关联的记录,查看 预加载 获取详情

4.6 Many2Many 的 CURD

查看 关联模式 获取 many2many 相关的用法

4.7 自3定义连接表

连接表 可以是一个全功能的模型,支持 Soft Delete钩子、更多的字段,就跟其它模型一样。您可以通过 SetupJoinTable 指定它,例如:

注意: 自定义连接表要求外键是复合主键或复合唯一索引

type Person struct {
ID int
Name string
Addresses []Address `gorm:"many2many:person_addresses;"`
} type Address struct {
ID uint
Name string
} type PersonAddress struct {
PersonID int `gorm:"primaryKey"`
AddressID int `gorm:"primaryKey"`
CreatedAt time.Time
DeletedAt gorm.DeletedAt
} func (PersonAddress) BeforeCreate(db *gorm.DB) error {
// ...
} // 修改 Person 的 Addresses 字段的连接表为 PersonAddress
// PersonAddress 必须定义好所需的外键,否则会报错
err := db.SetupJoinTable(&Person{}, "Addresses", &PersonAddress{})

4.8 外键约束

你可以通过为标签 constraint 配置 OnUpdateOnDelete 实现外键约束,在使用 GORM 进行迁移时它会被创建,例如:

type User struct {
gorm.Model
Languages []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.9 复合外键

如果您的模型使用了 复合主键,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 string
Body string
Tags []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"`
} // 连接表: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 // 连接表:locale_blog_tags
// foreign key: blog_id, reference: blogs.id
// foreign key: blog_locale, reference: blogs.locale
// foreign key: tag_id, reference: tags.id // 连接表:shared_blog_tags
// foreign key: blog_id, reference: blogs.id
// foreign key: tag_id, reference: tags.id

查看 复合主键 获取详情

五、实体关联

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 跳过自动创建、更新

若要在创建、更新时跳过自动保存,您可以使用 SelectOmit,例如:

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 user db.Omit(clause.Associations).Create(&user)
// Skip all associations when creating a user

NOTE: 对于 many2many 关联,GORM 在创建连接表引用之前,会先 upsert 关联。如果你想跳过关联的 upsert,你可以这样做:

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"},
} // 创建 user 及其 BillingAddress、ShippingAddress
// 在创建 BillingAddress 时,仅使用其 address1、address2 字段,忽略其它字段
db.Select("BillingAddress.Address1", "BillingAddress.Address2").Create(&user) db.Omit("BillingAddress.Address2", "BillingAddress.CreatedAt").Create(&user)

5.4 关联模式

关联模式包含一些在处理关系时有用的方法

// 开始关联模式
var user User
db.Model(&user).Association("Languages")
// `user` 是源模型,它的主键不能为空
// 关系的字段名是 `Languages`
// 如果匹配了上面两个要求,会开始关联模式,否则会返回错误
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 添加关联

many to manyhas 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 替换关联

用一个新的关联替换当前的关联

db.Model(&user).Association("Languages").Replace([]Language{languageZH, languageEN})

db.Model(&user).Association("Languages").Replace(Language{Name: "DE"}, languageEN)

5.4.4 删除关联

如果存在,则删除源模型与参数之间的关系,只会删除引用,不会从数据库中删除这些对象。

db.Model(&user).Association("Languages").Delete([]Language{languageZH, languageEN})
db.Model(&user).Association("Languages").Delete(languageZH, languageEN)

5.4.5 清空关联

删除源模型与关联之间的所有引用,但不会删除这些关联

db.Model(&user).Association("Languages").Clear()

5.4.6 关联计数

返回当前关联的计数

db.Model(&user).Association("Languages").Count()

// 条件计数
codes := []string{"zh-CN", "en-US", "ja-JP"}
db.Model(&user).Where("code IN ?", codes).Association("Languages").Count()

5.4.7 批量处理数据

关联模式也支持批量处理,例如:

// 查询所有用户的所有角色
db.Model(&users).Association("Role").Find(&roles) // 从所有 team 中删除 user A
db.Model(&users).Association("Team").Delete(&userA) // 获取去重的用户所属 team 数量
db.Model(&users).Association("Team").Count() // 对于批量数据的 `Append`、`Replace`,参数的长度必须与数据的长度相同,否则会返回 error
var users = []User{user1, user2, user3}
// 例如:现在有三个 user,Append userA 到 user1 的 team,Append userB 到 user2 的 team,Append userA、userB 和 userC 到 user3 的 team
db.Model(&users).Association("Team").Append(&userA, &userB, &[]User{userA, userB, userC})
// 重置 user1 team 为 userA,重置 user2 的 team 为 userB,重置 user3 的 team 为 userA、 userB 和 userC
db.Model(&users).Association("Team").Replace(&userA, &userB, &[]User{userA, userB, userC})

5.5 带 Select 的删除

你可以在删除记录时通过 Select 来删除具有 has one、has many、many2many 关系的记录,例如:

// 删除 user 时,也删除 user 的 account
db.Select("Account").Delete(&user) // 删除 user 时,也删除 user 的 Orders、CreditCards 记录
db.Select("Orders", "CreditCards").Delete(&user) // 删除 user 时,也删除用户所有 has one/many、many2many 记录
db.Select(clause.Associations).Delete(&user) // 删除 users 时,也删除每一个 user 的 account
db.Select("Account").Delete(&users)

注意: 只有当记录的主键不为空时,关联才会被删除,GORM 会使用这些主键作为条件来删除关联记录

// DOESN'T WORK
db.Select("Account").Where("name = ?", "jinzhu").Delete(&User{})
// 会删除所有 name=`jinzhu` 的 user,但这些 user 的 account 不会被删除 db.Select("Account").Where("name = ?", "jinzhu").Delete(&User{ID: 1})
// 会删除 name = `jinzhu` 且 id = `1` 的 user,并且 user `1` 的 account 也会被删除 db.Select("Account").Delete(&User{ID: 1})
// 会删除 id = `1` 的 user,并且 user `1` 的 account 也会被删除

5.6 关联标签(tag)

标签 描述
foreignKey 指定当前模型的列作为连接表的外键
references 指定引用表的列名,其将被映射为连接表外键
polymorphic 指定多态类型,比如模型名
polymorphicValue 指定多态值、默认表名
many2many 指定连接表表名
joinForeignKey 指定连接表的外键列名,其将被映射到当前表
joinReferences 指定连接表的外键列名,其将被映射到引用表
constraint 关系约束,例如:OnUpdateOnDelete

六 预加载

6.1 预加载

GORM 允许在 Preload 的其它 SQL 中直接加载关系,例如:

type User struct {
gorm.Model
Username string
Orders []Order
} type Order struct {
gorm.Model
UserID uint
Price float64
} // 查找 user 时预加载相关 Order
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 预加载

Preload 在一个单独查询中加载关联数据。而 Join Preload 会使用 inner join 加载关联数据,例如:

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

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, belongs to

6.3 预加载全部

与创建、更新时使用 Select 类似,clause.Associations 也可以和 Preload 一起使用,它可以用来 预加载 全部关联,例如:

type User struct {
gorm.Model
Name string
CompanyID uint
Company Company
Role Role
Orders []Order
} db.Preload(clause.Associations).Find(&users)

clause.Associations 不会预加载嵌套的关联,但你可以使用嵌套预加载 例如:

db.Preload("Orders.OrderItems.Product").Preload(clause.Associations).Find(&users)

6.4 带条件的预加载

GORM 允许带条件的 Preload 关联,类似于内联条件

// 带条件的预加载 Order
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 自定义预加载 SQL

您可以通过 func(db *gorm.DB) *gorm.DB 实现自定义预加载 SQL,例如:

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 嵌套预加载

GORM 支持嵌套预加载,例如:

db.Preload("Orders.OrderItems.Product").Preload("CreditCard").Find(&users)

// 自定义预加载 `Orders` 的条件
// 这样,GORM 就不会加载不匹配的 order 记录
db.Preload("Orders", "state = ?", "paid").Preload("Orders.OrderItems").Find(&users)

本文由博客一文多发平台 OpenWrite 发布!

Gorm 关联关系介绍与基本使用的更多相关文章

  1. golang gorm 基本使用

    原文链接:golang orm 框架之 gorm gorm 用法介绍 库安装 go get -u github.com/jinzhu/gorm 数据库连接 import ( "github. ...

  2. 【原】使用Bmob作为iOS后台开发心得——查询关联关系(BmobRelation)

    本文转载请注明出处 —— polobymulberry-博客园 简介 Bmob中的数据关联分为Pointer和Relation两种(数据关联在我开发app过程中使用还是很频繁的,也算个难点.虽然之前没 ...

  3. Storm介绍及与Spark Streaming对比

    Storm介绍 Storm是由Twitter开源的分布式.高容错的实时处理系统,它的出现令持续不断的流计算变得容易,弥补了Hadoop批处理所不能满足的实时要求.Storm常用于在实时分析.在线机器学 ...

  4. Enterprise Achitect使用与类的关系的简单介绍

    本文作为Enterprise Achitect初步使用,另外也是类图基本介绍,是设计模式的基础.  类的关系有泛化(Generalization).实现(Realization).依赖(Depende ...

  5. Python之路Day12--mysql介绍及操作

    上节回顾: 1. RabbitMQ a. 平均分发 b. perfetch = 1 c. durable 队列持久化  deliver_mode = 2 消息持久化 d. 1对多广播  exchang ...

  6. Hibernate —— 映射关联关系

    一.映射多对一关联关系. 1.单向的多对一 (1)以 Customer 和 Order 为例:一个用户可以发出多个订单,而一个订单只能属于一个客户.从 Order 到 Customer 是多对一关联关 ...

  7. #研发解决方案介绍#基于StatsD+Graphite的智能监控解决方案

    郑昀 基于李丹和刘奎的文档 创建于2014/12/5 关键词:监控.dashboard.PHP.graphite.statsd.whisper.carbon.grafana.influxdb.Pyth ...

  8. [UML]UML系列——类图class的关联关系(聚合、组合)

    关联的概念 关联用来表示两个或多个类的对象之间的结构关系,它在代码中表现为一个类以属性的形式包含对另一个类的一个或多个对象的应用. 程序演示:关联关系(code/assocation) 假设:一个公司 ...

  9. Python之路-python(mysql介绍和安装、pymysql、ORM sqlachemy)

    本节内容 1.数据库介绍 2.mysql管理 3.mysql数据类型 4.常用mysql命令 创建数据库 外键 增删改查表 5.事务 6.索引 7.python 操作mysql 8.ORM sqlac ...

  10. IntelliJ IDEA 编译方式介绍

    编译方式介绍 相比较于 Eclipse 的实时自动编译,IntelliJ IDEA 的编译更加手动化,虽然 IntelliJ IDEA 也支持通过设置开启实时编译,但是不建议,因为太占资源了.Inte ...

随机推荐

  1. 渗透测试 vs 漏洞扫描:差异与不同

    渗透测试和漏洞扫描常常被混淆,这两者都通过探索系统来寻找 IT 基础架构中的弱点及易受攻击的地方.阅读本文,带你了解两者之间的差异与不同. 手动 vs 自动 渗透测试是一种手动安全评估方式,网络安全人 ...

  2. 火山引擎 DataTester 科普:A/B 实验常见名词解释

    DataTester 是字节跳动在 2019 年正式通过火山引擎数智平台推出的对外服务的 A/B 实验工具,它基于先进的底层算法,提供科学分流能力,提供智能的统计引擎,实验结果可靠有效,助力业务决策. ...

  3. Neo4j Neo.TransientError.General.MemoryPoolOutOfMemoryError

    The allocation of an extra 4.0 MiB would use more than the limit 2.0 GiB. Currently using 2.0 GiB. d ...

  4. python 内置命名空间、标准库、模块相关概念

    内置命名空间 python 解释器启动后就可以直接使用一些函数,常量,类型,异常等.保存这些数据的空间统称内置命名空间. 内置命名空间中包含的数据如下: 对于内置命名空间中最常用的就是内置函数. 内置 ...

  5. 在Flutter中使用SetState无效?可能是忽略了这个!

    这次是Flutter开发技术分享,解决的问题点来自本人实际的开发经历. 首先描述一下问题:在某个组件中调用setState()方法更新该组件状态,结果是无法做到更新效果,组件仍然维持原状. 下面我们用 ...

  6. IDEA中无法import自己工程中类的问题解决方法

    今天开个很久没搞的工程,刚开的时候一片红,很自然的想到,要去配置一下项目的JDK,但是配置好之后,又出了个诡异问题:项目可以运行,但是import项目内部自己写的类的时候,都出现了红色错误.虽然imp ...

  7. es报错记录

    ElasticsearchException[failed to bind service]; nested: AccessDeniedException[/usr/share/elasticsear ...

  8. 6、SpringBoot-mybatis分页实现pagehelper

    系列导航 springBoot项目打jar包 1.springboot工程新建(单模块) 2.springboot创建多模块工程 3.springboot连接数据库 4.SpringBoot连接数据库 ...

  9. zzuli1895: 985的0-1串难题

    //解法:用二分查找,如果当前位置是'1',则查找比这个位置多k+1个零的位置,如果当前位置是'0',则查找比当前位置多k个零的位置, 注意要在末尾添个最大的值 #include<iostrea ...

  10. docker容器常用操作

    1.查看运行容器 docker ps:  2.查看所有容器 docker ps -a:  3.查看容器的日志 docker logs 容器名称/容器ID: 4.运行镜像 docker run --na ...