关联

多对多

qianmoQqianmoQ· 更新于 2026-09-23· 阅读 10 分钟· 0 次阅读

登录后可跨设备保存划线和私人笔记登录

多对多

多对多关系在两个模型之间添加一个关联表。

例如,如果您的应用包含用户和语言,一个用户可以说多种语言,而多个用户可以说指定的某种语言。


type User struct {
  gorm.Model
  Languages []Language `gorm:"many2many:user_languages;"`
}

type Language struct {
  gorm.Model
  Name string
}

当使用 GORM 的 AutoMigrate 为 User 创建表时,GORM 会自动创建关联表

反向引用

声明


type User struct {
  gorm.Model
  Languages []*Language `gorm:"many2many:user_languages;"`
}

type Language struct {
  gorm.Model
  Name string
  Users []*User `gorm:"many2many:user_languages;"`
}

检索


func GetAllUsers(db *gorm.DB) ([]User, error) {
  var users []User
  err := db.Model(&User{}).Preload("Languages").Find(&users).Error
  return users, err
}


func GetAllLanguages(db *gorm.DB) ([]Language, error) {
  var languages []Language
  err := db.Model(&Language{}).Preload("Users").Find(&languages).Error
  return languages, err
}

覆盖外键

对于 many2many 关系,关联表拥有引用两个模型的外键,例如:

type User struct {
  gorm.Model
  Languages []Language `gorm:"many2many:user_languages;"`
}

type Language struct {
  gorm.Model
  Name string
}



要覆盖它们,您可以使用标签 foreignKey、references、joinForeignKey、joinReferences,不必一起使用,只需使用其中之一即可覆盖部分外键/引用

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"`
}



注意:
某些数据库仅允许创建引用具有唯一索引字段的数据库外键,因此如果在迁移时创建数据库外键,需要指定 unique index 标签

自引用多对多

自引用的多对多关系

type User struct {
  gorm.Model
  Friends []*User `gorm:"many2many:user_friends"`
}



预加载

GORM 允许使用 Preload 预加载多对多关联,请参阅预加载(Eager loading)了解详情

多对多的增删改查

请查看关联模式以了解如何处理多对多关系

自定义关联表

JoinTable 可以是一个功能完整的模型,例如支持 软删除、钩子 以及更多字段,您可以使用 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 {
  
}



err := db.SetupJoinTable(&Person{}, "Addresses", &PersonAddress{})

外键约束

您可以使用 constraint 标签设置 OnUpdate、OnDelete 约束,它们将在使用 GORM 迁移时被创建,例如:

type User struct {
  gorm.Model
  Languages []Language `gorm:"many2many:user_speaks;"`
}

type Language struct {
  Code string `gorm:"primarykey"`
  Name string
}

您还可以在删除时使用 Select 删除选定的多对多关系,请查看使用 Select 删除了解详情

组合外键

如果您为模型使用了组合主键,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"`
}

另请查看组合主键

GitHub 标签(最新 SemVer)

评论

登录后参与评论

正在加载评论…