funcinit() { var err error //我这里用到数据库是mysql,需要配置DSN属性[username[:password]@][protocol[(address)]]/dbname[?param1=value1&...¶mN=valueN] dsn := "root:123456@tcp(127.0.0.1:3306)/go_test?charset=utf8&parseTime=True" db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{}) if err != nil { panic("failed to connect database") } }
1、Belongs To 属于
belongs to 会与另一个模型建立了一对一的连接。 这种模型的每一个实例都“属于”另一个模型的一个实例。
例如:你有两张表 users 表和 companies 表
users –用户表
companies –公司表
user 是属于 company 的,就是每个 user 有且只能对应分配给一个 company。
注意:在 User 对象中,有一个和 Company 一样的 CompanyID。 默认情况下, CompanyID 被隐含地用来在 User 和 Company 之间创建一个外键关系, 因此必须包含在 User 结构体中才能填充 Company 内部结构体。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
// `User` 属于 `Company`,`CompanyID` 是外键 type User struct { gorm.Model Name string CompanyID int// 默认情况下, CompanyID 被隐含地用来在 User 和 Company 之间创建一个外键关系 Company Company }
var u User db.Model(&User{}).Preload("Company").First(&u) fmt.Println(u)
3)重写外键
要定义一个 belongs to 关系,数据库的表中必须存在外键。默认gorm使用(关联属性类型 + 主键)组成外键名,如上面的例子User + ID 组成UserID,UserID就作为Profile的外键。
例如我们想自定义外键,就需要用标签foreignKe来指定外键:
1 2 3 4 5 6 7 8 9 10 11 12
type User struct { gorm.Model Name string CompanyRefer int Company Company `gorm:"foreignKey:CompanyRefer"` // 使用 CompanyRefer 作为外键 }
type Company struct { ID int Name string }
4)重写引用
对于 belongs to 关系,GORM 通常使用数据库表,主表(拥有者)的主键值作为外键参考。例如上面的例子,User 中 CompanyRefer 属性作为外键,它和Company 中的ID进行关联,这里 Company 的ID就是关联外键。
我们可以使用标签 references 来更改它,例如:
1 2 3 4 5 6 7 8 9 10 11 12
type User struct { gorm.Model Name string CompanyID string Company Company `gorm:"references:Code"`// 使用 Code 作为引用 }
type Company struct { ID int Code string Name string }
5)关联模式
a、查找关联
如果我们想查找指定的 user 匹配的关联记录,可以用Association找users表关联的记录:
1 2 3 4 5 6 7 8 9 10
var user User db.Where("id = ?", 1).Take(&user) fmt.Println(user)
var c Company // `user` 是源模型,它的主键不能为空 // 关系的字段名是 `Company` // 如果匹配了上面两个要求,会开始关联模式,否则会返回错误 db.Model(&user).Association("Company").Find(&c) fmt.Println(c)
b、删除关联
user 可以关联 company,同样也可以不关联,但是去库里删很麻烦,用Delete方法删除源模型与参数之间的关系,只会删除引用,不会从数据库中删除这些对象。
// User 有多张 CreditCard,UserID 是外键 type User struct { gorm.Model CreditCards []CreditCard }
type CreditCard struct { gorm.Model Number string UserID uint Info Info }
type Info struct { ID uint Name string Age int CreditCardID int }
使用之前预加载查询记录查询:
1 2 3
var user User db.Model(&User{}).Preload("CreditCards").Find(&user) fmt.Println(user)
我们只能查到主表对应关联的表结构记录,所以我们这里需要用到嵌套预加载的方式拿到我们需要的数据。
1 2 3 4
var user User //CreditCards.Info关联的下层结构 db.Model(&User{}).Preload("CreditCards.Info").Preload("CreditCards").Find(&user) fmt.Println(user)
或者 使用 自定义预加载 SQL:
1 2 3 4 5
var user User db.Model(&User{}).Preload("CreditCards", func(db *gorm.DB) *gorm.DB { return db.Preload("Info") }).Find(&user) fmt.Println(user)
3)带条件的预加载
有时候我们需要查询特定的关联结构记录时,可以使用带条件的 Preload 关联,类似于内联条件。
1 2 3 4
var user User //找到信用卡号不等于`123456`的记录 db.Model(&User{}).Preload("CreditCards.Info").Preload("CreditCards", "Number <> ?", "123456").Find(&user) fmt.Println(user)
var user User db.Model(&User{}).Preload("CreditCards.Info", "name <> ?", "linzy").Preload("CreditCards").Find(&user) fmt.Println(user)
他虽然满足了条件,但不是我们想要的结果,这个时候需要用到自定义加载SQL以及 Joins 预加载:
1 2 3 4 5
var user User db.Model(&User{}).Preload("CreditCards", func(db *gorm.DB) *gorm.DB { return db.Joins("Info").Where("name <> ?", "linzy") }).Find(&user) fmt.Println(user)
注意:Preload 在一个单独查询中加载关联数据。而 Join Preload 会使用 left join 加载关联数据。 Join Preload 适用于一对一的关系,例如: has one, belongs to。
4、多态关联
GORM 为 has one 和 has many 提供了多态关联支持,它会将拥有者实体的表名、主键都保存到多态类型的字段中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
type Dog struct { ID int Name string Toys []Toy `gorm:"polymorphic:Owner;"` }
type Toy struct { ID int Name string OwnerID int OwnerType string }