Has Many

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

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

声明

  1. // User 有多张 CreditCard,UserID 是外键
  2. type User struct {
  3. gorm.Model
  4. CreditCards []CreditCard
  5. }
  6. type CreditCard struct {
  7. gorm.Model
  8. Number string
  9. UserID uint
  10. }

检索

  1. // 检索用户列表并预加载信用卡
  2. func GetAll(db *gorm.DB) ([]User, error) {
  3. var users []User
  4. err := db.Model(&User{}).Preload("CreditCards").Find(&users).Error
  5. return users, err
  6. }

重写外键

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

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

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

  1. type User struct {
  2. gorm.Model
  3. CreditCards []CreditCard `gorm:"foreignKey:UserRefer"`
  4. }
  5. type CreditCard struct {
  6. gorm.Model
  7. Number string
  8. UserRefer uint
  9. }

重写引用

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

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

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

  1. type User struct {
  2. gorm.Model
  3. MemberNumber string
  4. CreditCards []CreditCard `gorm:"foreignKey:UserNumber;references:MemberNumber"`
  5. }
  6. type CreditCard struct {
  7. gorm.Model
  8. Number string
  9. UserNumber string
  10. }

多态关联

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

  1. type Dog struct {
  2. ID int
  3. Name string
  4. Toys []Toy `gorm:"polymorphic:Owner;"`
  5. }
  6. type Toy struct {
  7. ID int
  8. Name string
  9. OwnerID int
  10. OwnerType string
  11. }
  12. db.Create(&Dog{Name: "dog1", Toys: []Toy{{Name: "toy1"}, {Name: "toy2"}}})
  13. // INSERT INTO `dogs` (`name`) VALUES ("dog1")
  14. // INSERT INTO `toys` (`name`,`owner_id`,`owner_type`) VALUES ("toy1","1","dogs"), ("toy2","1","dogs")

您可以使用标签 polymorphicValue 来更改多态类型的值,例如:

  1. type Dog struct {
  2. ID int
  3. Name string
  4. Toys []Toy `gorm:"polymorphic:Owner;polymorphicValue:master"`
  5. }
  6. type Toy struct {
  7. ID int
  8. Name string
  9. OwnerID int
  10. OwnerType string
  11. }
  12. db.Create(&Dog{Name: "dog1", Toys: []Toy{{Name: "toy1"}, {Name: "toy2"}}})
  13. // INSERT INTO `dogs` (`name`) VALUES ("dog1")
  14. // INSERT INTO `toys` (`name`,`owner_id`,`owner_type`) VALUES ("toy1","1","master"), ("toy2","1","master")

Has Many 的 CURD

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

预加载

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

自引用 Has Many

  1. type User struct {
  2. gorm.Model
  3. Name string
  4. ManagerID *uint
  5. Team []User `gorm:"foreignkey:ManagerID"`
  6. }

外键约束

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

  1. type User struct {
  2. gorm.Model
  3. CreditCards []CreditCard `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
  4. }
  5. type CreditCard struct {
  6. gorm.Model
  7. Number string
  8. UserID uint
  9. }

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