GORM 支持四种主要的关联关系类型,每种关系都有其特定的使用场景和配置方式:
1. Belongs To(属于)
定义:一个模型属于另一个模型,外键在当前模型中。
示例:用户属于某个部门
gotype Department struct { ID uint Name string } type User struct { gorm.Model Name string DepartmentID uint Department Department `gorm:"foreignKey:DepartmentID"` } // 使用 var user User db.Preload("Department").First(&user, 1)
特点:
- 外键在子模型中
- 一对多关系的"多"方
- 使用
foreignKey标签指定外键字段
2. Has One(有一个)
定义:一个模型拥有另一个模型,外键在关联模型中。
示例:用户有一个信用卡
gotype CreditCard struct { gorm.Model Number string UserID uint User User `gorm:"foreignKey:UserID"` } type User struct { gorm.Model Name string CreditCard CreditCard } // 使用 var user User db.Preload("CreditCard").First(&user, 1)
特点:
- 外键在关联模型中
- 一对一关系
- 通常用于强关联的场景
3. Has Many(有多个)
定义:一个模型拥有多个关联模型,外键在关联模型中。
示例:用户有多个订单
gotype Order struct { gorm.Model UserID uint Amount float64 User User `gorm:"foreignKey:UserID"` } type User struct { gorm.Model Name string Orders []Order } // 使用 var user User db.Preload("Orders").First(&user, 1) // 条件预加载 db.Preload("Orders", "amount > ?", 100).First(&user, 1)
特点:
- 外键在关联模型中
- 一对多关系
- 最常用的关联类型
4. Many To Many(多对多)
定义:两个模型之间存在多对多关系,需要通过中间表(连接表)来实现。
示例:用户和角色的多对多关系
gotype User struct { gorm.Model Name string Roles []Role `gorm:"many2many:user_roles;"` } type Role struct { gorm.Model Name string Users []User `gorm:"many2many:user_roles;"` } // 使用 var user User db.Preload("Roles").First(&user, 1) // 添加关联 db.Model(&user).Association("Roles").Append(&Role{Name: "Admin"}) // 删除关联 db.Model(&user).Association("Roles").Delete(&Role{Name: "Admin"}) // 替换关联 db.Model(&user).Association("Roles").Replace(&Role{Name: "User"}) // 清空关联 db.Model(&user).Association("Roles").Clear() // 计数 count := db.Model(&user).Association("Roles").Count()
特点:
- 需要中间表(连接表)
- 默认中间表名为:table1_table2
- 可以自定义中间表名和字段
自定义关联配置
自定义外键
gotype User struct { gorm.Model CreditCards []CreditCard `gorm:"foreignKey:UserRefer"` } type CreditCard struct { gorm.Model Number string UserRefer uint }
自定义引用键
gotype User struct { gorm.Model Name string `gorm:"index"` CreditCard CreditCard `gorm:"foreignKey:UserName;references:Name"` } type CreditCard struct { gorm.Model Number string UserName string }
自定义多对多中间表
gotype User struct { gorm.Model Roles []Role `gorm:"many2many:user_roles;joinForeignKey:UserID;joinReferences:RoleID"` } type Role struct { gorm.Model Name string Users []User `gorm:"many2many:user_roles;"` }
预加载(Preload)
预加载用于解决 N+1 查询问题:
go// 基础预加载 db.Preload("Orders").Find(&users) // 嵌套预加载 db.Preload("Orders.Items").Find(&users) // 条件预加载 db.Preload("Orders", "status = ?", "completed").Find(&users) // 多个预加载 db.Preload("Orders").Preload("CreditCard").Find(&users)
关联操作
Association API
go// 查找关联 var roles []Role db.Model(&user).Association("Roles").Find(&roles) // 添加关联 db.Model(&user).Association("Roles").Append(&Role{Name: "Admin"}) // 删除关联 db.Model(&user).Association("Roles").Delete(&Role{Name: "Admin"}) // 替换关联 db.Model(&user).Association("Roles").Replace([]Role{role1, role2}) // 清空关联 db.Model(&user).Association("Roles").Clear() // 计数 count := db.Model(&user).Association("Roles").Count()
注意事项
- 外键命名:GORM 默认使用
{关联模型名}ID作为外键名 - 性能优化:合理使用预加载避免 N+1 查询
- 级联删除:默认情况下,删除主记录不会删除关联记录,需要手动配置
- 软删除:GORM 支持软删除,关联查询时需要注意软删除的记录
- 事务:复杂的关联操作建议在事务中执行