多对多

多对多

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

例如,如果您的应用程序包含用户和语言,并且一个用户可以讲多种语言,而多种语言可以由多个用户使用。

// User has and belongs to many languages, `user_languages` is the join table
type User struct {
gorm.Model
Languages []Language `gorm:"many2many:user_languages;"`
}

type Language struct {
gorm.Model
Name string
}

当使用 GORM AutoMigrateUser 创建表时,GORM 会自动创建连接表

反向引用

声明

// User has and belongs to many languages, use `user_languages` as join table
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 user list with eager loading languages
func GetAllUsers(db *gorm.DB) ([]User, error) {
var users []User
err := db.Model(&User{}).Preload("Languages").Find(&users).Error
return users, err
}

// Retrieve language list with eager loading users
func GetAllLanguages(db *gorm.DB) ([]Language, error) {
var languages []Language
err := db.Model(&Language{}).Preload("Users").Find(&languages).Error
return languages, err
}

覆盖外键

对于 多对多 关系,连接表拥有引用两个模型的外键,例如

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

type Language struct {
gorm.Model
Name string
}

// Join Table: user_languages
// foreign key: user_id, reference: users.id
// foreign key: language_id, reference: languages.id

要覆盖它们,您可以使用标签 foreignKeyreferencesjoinForeignKeyjoinReferences,不必同时使用它们,您可以只使用其中一个来覆盖某些外键/引用

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

// Which creates join table: user_profiles
// foreign key: user_refer_id, reference: users.refer
// foreign key: profile_refer, reference: profiles.user_refer

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

自引用多对多

自引用多对多关系

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

// Which creates join table: user_friends
// foreign key: user_id, reference: users.id
// foreign key: friend_id, reference: users.id

预加载

GORM 允许使用 Preload 预加载许多关联,有关详细信息,请参阅 预加载(预先加载)

使用多对多进行增删改查

请查看 关联模式 以了解如何使用多对多关系

自定义连接表

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 {
// ...
}

// Change model Person's field Addresses' join table to PersonAddress
// PersonAddress must defined all required foreign keys or it will raise error
err := db.SetupJoinTable(&Person{}, "Addresses", &PersonAddress{})

外键约束

您可以使用标签 constraint 设置 OnUpdateOnDelete 约束,它将在使用 GORM 迁移时创建,例如

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 删除选定的多对多关系,有关详细信息,请查看 使用选择删除

组合外键

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

// Join Table: 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

// Join Table: locale_blog_tags
// foreign key: blog_id, reference: blogs.id
// foreign key: blog_locale, reference: blogs.locale
// foreign key: tag_id, reference: tags.id

// Join Table: shared_blog_tags
// foreign key: blog_id, reference: blogs.id
// foreign key: tag_id, reference: tags.id

另请查看 组合主键

铂金赞助商

黄金赞助商

铂金赞助商

黄金赞助商