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 会自动创建连接表
AutoMigrate
User
// User 拥有并属于多种 language,`user_languages` 是连接表 type User struct { gorm.Model Languages []*Language `gorm:"many2many:user_languages;"` } type Language struct { gorm.Model Name string Users []*User `gorm:"many2many:user_languages;"` }
// 检索 User 列表并预加载 Language func GetAllUsers(db *gorm.DB) ([]User, error) { var users []User err := db.Model(&User{}).Preload("Languages").Find(&users).Error return users, err } // 检索 Language 列表并预加载 User func GetAllLanguages(db *gorm.DB) ([]Language, error) { var languages []Language err := db.Model(&Language{}).Preload("Users").Find(&languages).Error return languages, err }
对于 many2many 关系,连接表会同时拥有两个模型的外键,例如:
many2many
type User struct { gorm.Model Languages []Language `gorm:"many2many:user_languages;"` } type Language struct { gorm.Model Name string } // 连接表:user_languages // foreign key: user_id, reference: users.id // foreign key: language_id, reference: languages.id
若要重写它们,可以使用标签 foreignKey、references、joinforeignKey、joinReferences。当然,您不需要使用全部的标签,你可以仅使用其中的一个重写部分的外键、引用。
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"` } // 会创建连接表:user_profiles // foreign key: user_refer_id, reference: users.refer // foreign key: profile_refer, reference: profiles.user_refer
{% note warn %} 注意: 某些数据库只允许在唯一索引字段上创建外键,如果您在迁移时会创建外键,则需要指定 unique index 标签。 {% endnote %}
unique index
自引用 many2many 关系
type User struct { gorm.Model Friends []*User `gorm:"many2many:user_friends"` } // 会创建连接表:user_friends // foreign key: user_id, reference: users.id // foreign key: friend_id, reference: users.id
GORM 可以通过 Preload 预加载 has many 关联的记录,查看 预加载 获取详情
Preload
查看 关联模式 获取 many2many 相关的用法
JoinTable can be a full-featured model, like having Soft Delete,Hooks supports and more fields, you can set it up with SetupJoinTable, for example:
JoinTable
Soft Delete
Hooks
SetupJoinTable
{% note warn %} 注意: 自定义连接表要求外键是复合主键或复合唯一索引 {% endnote %}
type Person struct { ID int Name string Addresses []Address `gorm:"many2many:person_addressses;"` } 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 { // ... } // 修改 Person 的 Addresses 字段的连接表为 PersonAddress // PersonAddress 必须定义好所需的外键,否则会报错 err := db.SetupJoinTable(&Person{}, "Addresses", &PersonAddress{})
你可以通过为标签 constraint 配置 OnUpdate、OnDelete 实现外键约束,在使用 GORM 进行迁移时它会被创建,例如:
constraint
OnUpdate
OnDelete
type User struct { gorm.Model Languages []Language `gorm:"many2many:user_speaks;"` } type Language struct { Code string `gorm:"primarykey"` Name string } // CREATE TABLE `user_speaks` (`user_id` integer,`language_code` text,PRIMARY KEY (`user_id`,`language_code`),CONSTRAINT `fk_user_speaks_user` FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE SET NULL ON UPDATE CASCADE,CONSTRAINT `fk_user_speaks_language` FOREIGN KEY (`language_code`) REFERENCES `languages`(`code`) ON DELETE SET NULL ON UPDATE CASCADE);
你也可以在删除记录时通过 Select 来删除 many2many 关系的记录,查看 Delete with 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"` } // 连接表:blog_tags // foreign key: blog_id, reference: blogs.id // foreign key: blog_locale, reference: blogs.locale // foreign key: tag_id, reference: tags.id // foreign key: tag_locale, reference: tags.locale // 连接表:locale_blog_tags // foreign key: blog_id, reference: blogs.id // foreign key: blog_locale, reference: blogs.locale // foreign key: tag_id, reference: tags.id // 连接表:shared_blog_tags // foreign key: blog_id, reference: blogs.id // foreign key: tag_id, reference: tags.id
查看 复合主键 获取详情
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8