定义好关联关系后,需要操作这些关联。GORM 提供了
Association方法来管理关联数据。
获取关联模式:
var user User
db.First(&user, 1)
association := db.Model(&user).Association("Roles")
添加单个关联:
var role Role
db.First(&role, 1)
db.Model(&user).Association("Roles").Append(&role)
添加多个关联:
var roles []Role
db.Find(&roles, []int{1, 2, 3})
db.Model(&user).Association("Roles").Append(roles)
一对多关联同样适用:
var article Article
db.First(&article, 1)
db.Model(&user).Association("Articles").Append(&article)
替换所有关联:
var roles []Role
db.Find(&roles, []int{4, 5, 6})
db.Model(&user).Association("Roles").Replace(roles)
用户原来的角色会被删除,替换为新角色。
删除单个关联:
var role Role
db.First(&role, 1)
db.Model(&user).Association("Roles").Delete(&role)
删除多个关联:
var roles []Role
db.Find(&roles, []int{1, 2})
db.Model(&user).Association("Roles").Delete(roles)
注意:只删除关联关系,不删除关联对象本身。
清空所有关联:
db.Model(&user).Association("Roles").Clear()
count := db.Model(&user).Association("Roles").Count()
fmt.Printf("用户有 %d 个角色\n", count)
var roles []Role
db.Model(&user).Association("Roles").Find(&roles)
带条件查询:
var roles []Role
db.Model(&user).Association("Roles").Find(&roles, "name LIKE ?", "%admin%")
检查是否有关联:
var role Role
db.First(&role, 1)
hasRole := db.Model(&user).Association("Roles").Contains(&role)
fmt.Println(hasRole)
操作多个对象的关联:
var users []User
db.Find(&users, []int{1, 2, 3})
var role Role
db.First(&role, 1)
db.Model(&users).Association("Roles").Append(&role)
给所有用户添加同一个角色。
| 方法 | 说明 |
|---|---|
| Append | 添加关联 |
| Replace | 替换关联 |
| Delete | 删除关联 |
| Clear | 清空关联 |
| Count | 统计数量 |
| Find | 查询关联 |
| Contains | 检查关联 |
在模型定义中配置关联行为:
type User struct {
ID uint
Roles []Role `gorm:"many2many:user_roles;constraint:OnDelete:CASCADE;"`
}
常用标签:
foreignKey - 外键字段references - 引用字段many2many - 多对多中间表polymorphic - 多态关联polymorphicValue - 多态类型值constraint - 外键约束OnDelete - 删除行为OnUpdate - 更新行为创建时级联:
user := User{
Name: "张三",
Roles: []Role{
{Name: "admin"},
{Name: "editor"},
},
}
db.Create(&user)
删除时级联:
db.Select("Roles").Delete(&user)
删除用户同时删除关联的角色(多对多会删除中间表记录)。
删除关联对象:
db.Select("Articles").Delete(&user)
删除用户同时删除用户的文章。
更新关联对象:
var user User
db.Preload("Profile").First(&user, 1)
user.Profile.Bio = "新简介"
db.Save(&user)
或者:
db.Model(&user).Association("Profile").Update(&Profile{Bio: "新简介"})
只创建关联:
var user User
db.First(&user, 1)
article := Article{Title: "新文章"}
db.Model(&user).Association("Articles").Append(&article)
用户角色管理
func AssignRole(db *gorm.DB, userID uint, roleIDs []uint) error {
var user User
if err := db.First(&user, userID).Error; err != nil {
return err
}
var roles []Role
if err := db.Find(&roles, roleIDs).Error; err != nil {
return err
}
return db.Model(&user).Association("Roles").Replace(roles)
}
func AddRole(db *gorm.DB, userID uint, roleID uint) error {
var user User
var role Role
if err := db.First(&user, userID).Error; err != nil {
return err
}
if err := db.First(&role, roleID).Error; err != nil {
return err
}
return db.Model(&user).Association("Roles").Append(&role)
}
func RemoveRole(db *gorm.DB, userID uint, roleID uint) error {
var user User
var role Role
if err := db.First(&user, userID).Error; err != nil {
return err
}
if err := db.First(&role, roleID).Error; err != nil {
return err
}
return db.Model(&user).Association("Roles").Delete(&role)
}
文章标签管理
func UpdateTags(db *gorm.DB, articleID uint, tagNames []string) error {
var article Article
if err := db.First(&article, articleID).Error; err != nil {
return err
}
var tags []Tag
for _, name := range tagNames {
var tag Tag
db.FirstOrCreate(&tag, Tag{Name: name})
tags = append(tags, tag)
}
return db.Model(&article).Association("Tags").Replace(tags)
}
关联不存在
操作不存在的关联会报错:
var user User
db.Model(&user).Association("Roles").Append(&role)
用户没有 ID,无法操作关联。确保对象已存在。
关联名称错误
db.Model(&user).Association("Role")
模型定义是 Roles,写错会报错。
零值问题
var role Role
db.Model(&user).Association("Roles").Delete(&role)
role 是零值,删除操作无效。确保关联对象有效。
Association 方法提供了灵活的关联操作能力。掌握添加、删除、替换、查询这些操作,能有效管理模型间的关联关系。