文章目录
一 关联—Belongs To
1.1 Belongs To
belongs to
会与另一个模型建立了一对一的连接。 这种模型的每一个实例都“属于”另一个模型的一个实例。
例如,您的应用包含 user 和 company,并且每个 user 能且只能被分配给一个 company。下面的类型就表示这种关系。 注意,在 User
对象中,有一个和 Company
一样的 CompanyID
。 默认情况下, CompanyID
被隐含地用来在 User
和 Company
之间创建一个外键关系, 因此必须包含在 User
结构体中才能填充 Company
内部结构体。
// `User` 属于 `Company`,`CompanyID` 是外键
type User struct {
gorm.Model
Name string
CompanyID int
Company Company
}
type Company struct {
ID int
Name string
}
请参阅 预加载 以了解内部结构的详细信息。
1.2 重写外键
要定义一个 belongs to 关系,数据库的表中必须存在外键。默认情况下,外键的名字,使用拥有者的类型名称加上表的主键的字段名字
例如,定义一个User实体属于Company实体,那么外键的名字一般使用CompanyID。
GORM同时提供自定义外键名字的方式,如下例所示。
type User struct {
gorm.Model
Name string
CompanyRefer int
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
CompanyID string
Company Company `gorm:"references:Code"` // 使用 Code 作为引用
}
type Company struct {
ID int
Code string
Name string
}
NOTE GORM usually guess the relationship as
has one
if override foreign key name already exists in owner’s type, we need to specifyreferences
in thebelongs to
relationship.
type User struct {
gorm.Model
Name string
CompanyID string
Company Company `gorm:"references:CompanyID"` // use Company.CompanyID as references
}
type Company struct {
CompanyID int
Code string
Name string
}
1.4 Belongs to 的 CRUD
Please checkout Association Mode for working with belongs to relations
1.5 预加载
GORM allows eager loading belongs to associations with Preload
or Joins
, refer Preloading (Eager loading) for details
1.6 外键约束
You can setup OnUpdate
, OnDelete
constraints with tag constraint
, it will be created when migrating with GORM, for example:
type User struct {
gorm.Model
Name string
CompanyID int
Company Company `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
}
type Company struct {
ID int
Name string
}
二 关联—Has One
2.1 Has One
has one
与另一个模型建立一对一的关联,但它和一对一关系有些许不同。 这种关联表明一个模型的每个实例都包含或拥有另一个模型的一个实例。
例如,您的应用包含 user 和 credit card 模型,且每个 user 只能有一张 credit card。
2.1.1 Declare
// User 有一张 CreditCard,UserID 是外键
type User struct {
gorm.Model
CreditCard CreditCard
}
type CreditCard struct {
gorm.Model
Number string
UserID uint
}
2.1.2 Retrieve
// Retrieve user list with eager loading credit card
func GetAll(db *gorm.DB) ([]User, error) {
var users []User
err := db.Model(&User{
}).Preload("CreditCard").Find(&users).Error
return users, err
}
2.2 重写外键
对于 has one
关系,同样必须存在外键字段。拥有者将把属于它的模型的主键保存到这个字段。
这个字段的名称通常由 has one
模型的类型加上其 主键
生成,对于上面的例子,它是 UserID
。
为 user 添加 credit card 时,它会将 user 的 ID
保存到自己的 UserID
字段。
如果你想要使用另一个字段来保存该关系,你同样可以使用标签 foreignKey
来更改它,例如:
type User struct {
gorm.Model
CreditCard CreditCard `gorm:"foreignKey:UserName"`
// use UserName as foreign key
}
type CreditCard struct {
gorm.Model
Number string
UserName string
}
2.3 重写引用
默认情况下,拥有者实体会将 has one
对应模型的主键保存为外键,您也可以修改它,用另一个字段来保存,例如下个这个使用 Name
来保存的例子。
您可以使用标签 references
来更改它,例如:
type User struct {
gorm.Model
Name string `gorm:"index"`
CreditCard CreditCard `gorm:"foreignkey:UserName;references:name"`
}
type CreditCard struct {
gorm.Model
Number string
UserName string
}
2.4 多态关联
GORM 为 has one
和 has 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 可以通过 Preload
、Joins
预加载 has one
关联的记录,查看 预加载 获取详情
2.7 自引用 Has One
type User struct {
gorm.Model
Name string
ManagerID *uint
Manager *User
}
2.8 外键约束
你可以通过为标签 constraint
配置 OnUpdate
、OnDelete
实现外键约束,在使用 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。
3.1.1 Declare
// User 有多张 CreditCard,UserID 是外键
type User struct {
gorm.Model
CreditCards []CreditCard
}
type CreditCard struct {
gorm.Model
Number string
UserID uint
}
3.1.2 Retrieve
// Retrieve user list with edger loading credit cards
func GetAll(db *gorm.DB) ([]User, error) {
var users []User
err := db.Model(&User{
}).Preload("CreditCards").Find(&users).Error
return users, err
}
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 通常使用拥有者的主键作为外键的值。 对于上面的例子,它是 User
的 ID
字段。
为 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 one
和 has 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", Toy: []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
配置 OnUpdate
、OnDelete
实现外键约束,在使用 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 的 AutoMigrate
为 User
创建表时,GORM 会自动创建连接表