InfoSphere/GORM 中文版/ 返回书籍
Associations

Many To Many

qianmoQqianmoQ· 更新于 2026-09-14· 阅读 13 分钟· 0 次阅读

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

Many To Many

Many to Many add a join table between two models.

For example, if your application includes users and languages, and a user can speak many languages, and many users can speak a specified language.


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

type Language struct {
  gorm.Model
  Name string
}

When using GORM AutoMigrate to create a table for User, GORM will create the join table automatically

Back-Reference

Declare


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

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

Retrieve


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
}

Override Foreign Key

For a many2many relationship, the join table owns the foreign key which references two models, for example:

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

type Language struct {
  gorm.Model
  Name string
}



To override them, you can use tag foreignKey, references, joinForeignKey, joinReferences, not necessary to use them together, you can just use one of them to override some foreign keys/references

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



NOTE:
Some databases only allow create database foreign keys that reference on a field having unique index, so you need to specify the unique index tag if you are creating database foreign keys when migrating

Self-Referential Many2Many

Self-referencing many2many relationship

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



Eager Loading

GORM allows eager loading has many associations with Preload, refer Preloading (Eager loading) for details

CRUD with Many2Many

Please checkout Association Mode for working with many2many relations

Customize JoinTable

JoinTable can be a full-featured model, like having Soft DeleteHooks supports and more fields, you can set it up with SetupJoinTable, for example:

NOTE:
Customized join table’s foreign keys required to be composited primary keys or composited unique index

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{})

FOREIGN KEY Constraints

You can setup OnUpdate, OnDelete constraints with tag constraint, it will be created when migrating with GORM, for example:

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

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

You are also allowed to delete selected many2many relations with Select when deleting, checkout Delete with Select for details

Composite Foreign Keys

If you are using Composite Primary Keys for your models, GORM will enable composite foreign keys by default

You are allowed to override the default foreign keys, to specify multiple foreign keys, just separate those keys’ name by commas, for example:

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

Also check out Composite Primary Keys

GitHub tag (latest SemVer)

评论

登录后参与评论

正在加载评论…