我们接上篇文章,地址gorm 实战 | 青训营 - 掘金 (juejin.cn)
上篇文章主要业务场景为:短视频点关注操作
下面,我们进行查询操作,业务描述如下:
用户登录:
成功 ——> 获取用户关注列表 | 获取用户粉丝列表
回顾之前model模型
model
type Model struct {
ID int64 `json:"id" gorm:"primarykey;comment:主键"`
CreatedAt time.Time `json:"-" gorm:"comment:创建时间"`
UpdatedAt time.Time `json:"-" gorm:"comment:修改时间"`
DeletedAt gorm.DeletedAt `json:"-" gorm:"comment:删除时间"`
}
user
type (
// User 用户信息表
User struct {
Model
Name string `json:"name" gorm:"index:,unique;size:32;comment:用户名称"`
Pawd string `json:"-" gorm:"size:128;comment:用户密码"`
Avatar string `json:"avatar" gorm:"comment:用户头像"`
BackgroundImage string `json:"background_image" gorm:"comment:用户个人页顶部大图"`
Signature string `json:"signature" gorm:"default:此人巨懒;comment:个人简介"`
WorkCount int64 `json:"work_count" gorm:"default:0;comment:作品数量"`
Follow []*User `json:"follow,omitempty" gorm:"many2many:UserFollow;comment:关注列表"`
}
)
我们还是使用单数命名表策略,策略使用只需在连接数据库时候,在&gorm.Config{},中将SingularTable: true
db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
NamingStrategy: schema.NamingStrategy{
SingularTable: true, //表名以单数形式命名
},
TranslateError: true, // 启用错误翻译功能
})
ok!!!,会在数据库中创建两个表,我介绍下,首先一定有user表,其次就是一个中间表user_follow,中间表user_follow会有两个字段,一个为user_id,一个为follow_id,这两个字段都是外键,都引用user表的id字段,同时又是联合主键
CREATE TABLE
user_follow
(user_id
bigint NOT NULL COMMENT '主键',
follow_id
bigint NOT NULL COMMENT '主键',
PRIMARY KEY (user_id
,follow_id
),
KEYfk_user_follow_follow
(follow_id
),
CONSTRAINTfk_user_follow_follow
FOREIGN KEY (follow_id
) REFERENCESuser
(id
),
CONSTRAINTfk_user_follow_user
FOREIGN KEY (user_id
) REFERENCESuser
(id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
ok!!!,我下面来介绍获取用户关注列表
的实现:
// RelationFollowGet 获取关注列表 uid:本人id tid:待查id
func RelationFollowGet(uid, tid int64) ([]*model.User, error) {
var data []*model.User
err := db.Set("user_id", uid).Model(&model.User{Model: id(tid)}).Association("Follow").Find(&data)
if err != nil {
return nil, err
}
return data, nil
}
执行的底层sql大致如下:
SELECTuser
.* FROMuser
JOINuser_follow
ONuser_follow
.follow_id
=user
.id
ANDuser_follow
.user_id
= ? WHEREuser
.deleted_at
IS NULL;
获取用户粉丝列表
这里我们不能使用Association,Association 是获取指定模型关联的数据,我们这里是给定关联数据,即用户id(谁关注该用户),来反向获取id
// RelationFollowerGet 获取粉丝列表 uid:本人id tid:待查id
func RelationFollowerGet(uid, tid int64) ([]*model.User, error) {
var data []*model.User
err := db.Set("user_id", uid).Table("user").
Joins("JOIN user_follow ON `user`.`id` = `user_follow`.`user_id` AND `user_follow`.`follow_id` = ?", tid).
Select("`user`.*").Find(&data).Error
if err != nil {
return nil, err
}
return data, nil
}
执行sql一眼就知:
SELECTuser
.* FROMuser
JOINuser_follow
ONuser
.id
=user_follow
.user_id
ANDuser_follow
.follow_id
= ? WHEREuser
.deleted_at
IS NULL;
Association在GORM中是一个重要的概念,它表示模型之间的关联关系。
更详细地介绍Association:
- 表示关系
Association表示数据库表之间的关系,如一对一、一对多和多对多等关系。
- 类型
- BelongsTo:一对一,参照型,Inverse 位于belongs to一方
- HasOne:一对一,拥有型
- HasMany:一对多
- ManyToMany:多对多
- 定义
通过模型字段定义Association关系,如:
type Order struct {
Product Product `gorm:"association_autoupdate:false"`
}
- 查询
通过Association进行关联查询,如Preload预加载避免N+1。
- 操作
如Append/Delete对关联记录执行操作。
- 定制
通过Query等定制关联查询条件。
- 更新
根据Inverse或own自身更新关联记录。
- Constraints
设置外键等约束。
- 逆向引用
通过BelongsTo.AssociationGetField访问逆向引用。
- 节省内存
通过RowsBackedAssociation避免重复读取关联记录。
Association利用关系对数据库操作进行抽象,大大简化了关系型数据库的使用难度。深入了解它可以更高效使用GORM开发项目。