type User struct {
orm.Model
Name string
Phone *Phone `gorm:"foreignKey:UserName"`
}
type Phone struct {
orm.Model
UserName string
Name string
}
另外,Orm 假设外键的值是与父模型的主键(Primary Key)相同的。换句话说,Orm 将会通过 Phone 记录的 UserID 列中查找与用户表的 id 列相匹配的值。如果你希望使用自定义的主键值,可以在 User 模型中为 Phone 字段添加 references Tag(其他关联关系类同):
type User struct {
orm.Model
Name string
Phone *Phone `gorm:"foreignKey:UserName;references:name"`
}
type Phone struct {
orm.Model
UserName string
Name string
}
定义反向关联
我们已经能从 User 模型访问到 Phone 模型了。接下来,让我们再在 Phone 模型上定义一个关联,它能让我们访问到拥有该电话的用户。我们可以在 Phone 模型中定义一个 User 字段:
type User struct {
orm.Model
Name string
}
type Phone struct {
orm.Model
UserID uint
Name string
User *User
}
users
id - integer
name - string
roles
id - integer
name - string
role_user
user_id - integer
role_id - integer
模型结构
我们可以在 User 模型上定义一个 Roles 字段:
type User struct {
orm.Model
Name string
Roles []*Role `gorm:"many2many:role_user"`
}
type Role struct {
orm.Model
Name string
}
定义反向关联
要定义多对多的反向关联,只需要在 Role 模型中定义 Users 字段并附加 Tag:
type User struct {
orm.Model
Name string
Roles []*Role `gorm:"many2many:role_user"`
}
type Role struct {
orm.Model
Name string
Users []*User `gorm:"many2many:role_user"`
}
type User struct {
orm.Model
Name string
Roles []*Role `gorm:"many2many:role_user;joinForeignKey:UserName;joinReferences:RoleName"`
}
type Role struct {
orm.Model
Name string
}
对应表结构:
users
id - integer
name - string
roles
id - integer
name - string
role_user
user_name - integer
role_name - integer
多态
多态关联允许目标模型借助单个关联从属于多个模型。例如,你正在构建一个允许用户共享博客文章和视频的应用程序,其中 Comment 模型可能同时从属于 Post 和 Video 模型。目前仅有 One To One 与 One To Many 支持多态。
表结构
多态关联与简单的关联类似,不过,目标模型能够在一个关联上从属于多个模型。例如,博客 Post 和 Video 可能共享一个关联到 Image 模型的关系,同时共享多个关联到 Comment 模型。让我们先看看表结构:
posts
id - integer
name - string
videos
id - integer
name - string
images
id - integer
url - string
imageable_id - integer
imageable_type - string
comments
id - integer
body - text
commentable_id - integer
commentable_type - string
user := User{Name: "user", Post: &Post{Name: "post"}}
// 创建 User 的同时创建所有子关联
facades.Orm().Query().Select(orm.Associations).Create(&user)
// 创建 User 的同时只创建 Post 子关联。注意:如果不使用 `orm.Associations`,而是单独自定义特定子关联,则此时也应将所有父模型中的字段列出。
facades.Orm().Query().Select("Name", "Post").Create(&user)
// 创建 User 时,忽略 Post 关联,但创建其他所有子关联
facades.Orm().Query().Omit("Post").Create(&user)
// 创建 User 时,忽略 Name 字段,但创建所有子关联
facades.Orm().Query().Omit("Name").Create(&user)
// 创建 User 时,忽略 Name 字段与所有子关联
facades.Orm().Query().Omit("Name", orm.Associations).Create(&user)
// 查询所有用户的所有文章
facades.Orm().Query().Model(&users).Association("Posts").Find(&posts)
// 从所有 Post 中删除 user A
facades.Orm().Query().Model(&users).Association("Posts").Delete(&userA)
// 获取去重的用户所属 Post 数量
facades.Orm().Query().Model(&users).Association("Posts").Count()
// 对于批量数据的 `Append`、`Replace`,参数的长度必须与数据的长度相同,否则会返回 error
var users = []User{user1, user2, user3}
// 有三个 user,Append userA 到 user1 的 team,Append userB 到 user2 的 team,Append userA、userB 和 userC 到 user3 的 team
facades.Orm().Query().Model(&users).Association("Team").Append(&userA, &userB, &[]User{userA, userB, userC})
// 重置 user1 team 为 userA,重置 user2 的 team 为 userB,重置 user3 的 team 为 userA、 userB 和 userC
facades.Orm().Query().Model(&users).Association("Team").Replace(&userA, &userB, &[]User{userA, userB, userC})
预加载
预加载为多个模型的查询提供方便,同时减轻了 N + 1 查询问题。 为了说明 N + 1 查询问题,请参考属于 Author 模型的 Book 模型:
type Author struct {
orm.Model
Name string
}
type Book struct {
orm.Model
AuthorID uint
Name string
Author *Author
}
我们检索所有书籍及其作者:
var books models.Book
facades.Orm().Query().Find(&books)
for _, book := range books {
var author models.Author
facades.Orm().Query().Find(&author, book.AuthorID)
}
var books models.Book
facades.Orm().Query().Find(&books)
for _, book := range books {
if someCondition {
err := facades.Orm().Query().Load(&book, "Author")
}
}