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

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

Back-Reference

  1. // User has and belongs to many languages, use `user_languages` as join table
  2. type User struct {
  3. gorm.Model
  4. Languages []*Language `gorm:"many2many:user_languages;"`
  5. }
  6. type Language struct {
  7. gorm.Model
  8. Name string
  9. Users []*User `gorm:"many2many:user_languages;"`
  10. }

Override Foreign Key

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

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

  1. type User struct {
  2. gorm.Model
  3. Profiles []Profile `gorm:"many2many:user_profiles;foreignKey:Refer;joinForeignKey:UserReferID;References:UserRefer;joinReferences:ProfileRefer"`
  4. Refer uint `gorm:"index:,unique"`
  5. }
  6. type Profile struct {
  7. gorm.Model
  8. Name string
  9. UserRefer uint `gorm:"index:,unique"`
  10. // Which creates join table: user_profiles
  11. // foreign key: user_refer_id, reference: users.refer

Self-referencing many2many relationship

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

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

  1. type Person struct {
  2. ID int
  3. Name string
  4. Addresses []Address `gorm:"many2many:person_addresses;"`
  5. }
  6. type Address struct {
  7. ID uint
  8. Name string
  9. }
  10. type PersonAddress struct {
  11. PersonID int `gorm:"primaryKey"`
  12. AddressID int `gorm:"primaryKey"`
  13. CreatedAt time.Time
  14. DeletedAt gorm.DeletedAt
  15. }
  16. func (PersonAddress) BeforeCreate(db *gorm.DB) error {
  17. // ...
  18. }
  19. // Change model Person's field Addresses' join table to PersonAddress
  20. // PersonAddress must defined all required foreign keys or it will raise error
  21. err := db.SetupJoinTable(&Person{}, "Addresses", &PersonAddress{})

FOREIGN KEY Constraints

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

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:

  1. ID uint `gorm:"primaryKey"`
  2. Locale string `gorm:"primaryKey"`
  3. Value string
  4. }
  5. type Blog struct {
  6. ID uint `gorm:"primaryKey"`
  7. Locale string `gorm:"primaryKey"`
  8. Subject string
  9. Body string
  10. Tags []Tag `gorm:"many2many:blog_tags;"`
  11. LocaleTags []Tag `gorm:"many2many:locale_blog_tags;ForeignKey:id,locale;References:id"`
  12. SharedTags []Tag `gorm:"many2many:shared_blog_tags;ForeignKey:id;References:id"`
  13. }
  14. // Join Table: blog_tags
  15. // foreign key: blog_id, reference: blogs.id
  16. // foreign key: blog_locale, reference: blogs.locale
  17. // foreign key: tag_id, reference: tags.id
  18. // foreign key: tag_locale, reference: tags.locale
  19. // Join Table: locale_blog_tags
  20. // foreign key: blog_id, reference: blogs.id
  21. // foreign key: blog_locale, reference: blogs.locale
  22. // foreign key: tag_id, reference: tags.id
  23. // Join Table: shared_blog_tags
  24. // foreign key: tag_id, reference: tags.id