[TOC]
说明
请先阅读官方文档,由于官方文档对每个例子和概念解释比较简单,官方文档中个人认为比较难理解的概念在正文章节进行解释
本文须与官方文档伴食,否则将不知所云。
可对应 学习项目 实践验证。
参考
正文
关系
foreignkey & association foreignkey
//情况A:不指定外键和关联外键
type User struct {
gorm.Model
CreditCard CreditCard
}
type CreditCard struct {
gorm.Model
UserID uint
Number string
}
//情况B:外键和关联外键
type User struct {
gorm.Model
Refer string
CreditCard CreditCard `gorm:"ForeignKey:ReferRela;AssociationForeignKey:Refer"`
}
type CreditCard struct {
gorm.Model
ReferRela uint
Number string
}
理解:
- 在情况A下,默认
credit_cards.user_id
为ForeignKey
,对应users.id
为AssociationForeignKey
,即某条users
表的记录id=1234
,那么credit_cards
表中的user_id=1234
的记录属于与其对应; - 在情况B下,由于显式指定了外键和关联外键,则
credit_cards.refer_rela
对应users.refer
;
后文多种关系中都涉及此两键,但是在 Many to Many 关联关系中使用方式稍有不同。
foreignkey:B 表关联 A 表的字段association foreignkey:A 表被 B 表关联的字段
即:A 表的association foreignkey对应 B表的foreignkey,两表两值相等的记录具有关联关系。
后文多种关系中都涉及此两个键,用法是一样的。默认不指定的时候 A 表的association foreignkey为其primary key,B 表的foreignkey为 A 表表名+A 表 primary key。
Belongs To & Has One
//Profile Belongs To User
type User struct {
gorm.Model
Name string
}
// `Profile` 属于 `User`, 外键是`UserID`
type Profile struct {
gorm.Model
UserID int
User User
Name string
}
//User Has One Profile
type User struct {
gorm.Model
Name string
Profile Profile
}
// `Profile` 属于 `User`, 外键是`UserID`
type Profile struct {
gorm.Model
UserID int
Name string
}
理解:
两者区别在于主体(主语)不同,在逻辑上孪生:
- Belongs To :以 Profile 为主体,Profile属于 User。——Profile 内持有 User;
- Has One:以 User 为主体,User 拥有 Profile。——User 内持有 Profile。
两者的ForeignKey
和AssociationForeignKey
关系是一样的,都是在 Profile 里定义ForeignKey
——Profile.UserID
,其对应的是User的PrimerKey
(即AssociationForeignKey
)——User.ID
根据以上两种定义方式在数据库创建表结构没有差别,但在应用程序内对数据操作有区别(设计目的|效果)。就查询而言,前者可以查询出携带对应 User 信息的 Profile;后者可以查询出携带对应 Profile 信息的 User。
多态关联
除Many To 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
}
理解:toys.owner_id
对应cats.id
和dogs.id
,toys.owner_type
对应cat
和dog
。
Has Many & Many To Many
通过切片指定对多关系
`gorm:"many2many:关系表命;"`指定多对多关系
在Many To Many中foreignkey & association foreignkey不做方向区分,都是指定关系表对应的实体表字段
association_jointable_foreignkey&jointable_foreignkey指定关系表中字段名
关系的使用
通过 gorm.DB.Set(xxx)
或者 Struct Tag 定义关系行为:
- gorm:association_autoupdate——自动更新关联开关
- gorm:association_autocreate——自动创建关联开关
- gorm: save_associations——前两者的和
- gorm:association_save_reference——关联引用保存开关
// Set set setting by name, which could be used in callbacks, will clone a new db, and update its setting
func (s *DB) Set(name string, value interface{}) *DB {
return s.clone().InstantSet(name, value)
}
根据 Set 方法的注释说明,返回的是 DB 的副本,则此设置只在一次 DB 构造执行中有效。
方法
db.Model(&user).Association("Languages")
指定表、记录 ID
指定字段
后面跟操作方法如下
- Find(&languages)——查询匹配的关联记录
- Append(Language{Name: "DE"})——添加关联
- Replace([]Language{languageZH, languageEN})——替换关联
- Delete([]Language{languageZH, languageEN})——删除关联
- Clear()——清空关联
- Count()——返回关联记录数量
Preloading (预加载)
Preload("Orders")
和Find(&users)
实际作用与语义刚好相反。
- 从方法语义来说,只管感觉是加载 Orders 表记录,根据 Orders 记录查询所有关联的 Users 记录
- 实际过程是,加载 Users 记录,更具 Users 记录查询关联的 Orders 记录
并且可以在 Preload 内指定 Orders 的筛选条件,可以配合 Where 方法指定 Users 的筛选条件。