乐闻世界logo
搜索文章和话题

GORM 中的关联关系有哪些类型?

3月6日 21:37

GORM 支持四种主要的关联关系类型,每种关系都有其特定的使用场景和配置方式:

1. Belongs To(属于)

定义:一个模型属于另一个模型,外键在当前模型中。

示例:用户属于某个部门

go
type 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(有一个)

定义:一个模型拥有另一个模型,外键在关联模型中。

示例:用户有一个信用卡

go
type 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(有多个)

定义:一个模型拥有多个关联模型,外键在关联模型中。

示例:用户有多个订单

go
type 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(多对多)

定义:两个模型之间存在多对多关系,需要通过中间表(连接表)来实现。

示例:用户和角色的多对多关系

go
type 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
  • 可以自定义中间表名和字段

自定义关联配置

自定义外键

go
type User struct { gorm.Model CreditCards []CreditCard `gorm:"foreignKey:UserRefer"` } type CreditCard struct { gorm.Model Number string UserRefer uint }

自定义引用键

go
type User struct { gorm.Model Name string `gorm:"index"` CreditCard CreditCard `gorm:"foreignKey:UserName;references:Name"` } type CreditCard struct { gorm.Model Number string UserName string }

自定义多对多中间表

go
type 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()

注意事项

  1. 外键命名:GORM 默认使用 {关联模型名}ID 作为外键名
  2. 性能优化:合理使用预加载避免 N+1 查询
  3. 级联删除:默认情况下,删除主记录不会删除关联记录,需要手动配置
  4. 软删除:GORM 支持软删除,关联查询时需要注意软删除的记录
  5. 事务:复杂的关联操作建议在事务中执行
标签:Gorm