golang-GORM的使用

826 阅读2分钟

写作目的

自己在使用GORM时,感觉到有些力不从心(我必须得按照它的Model定义来使用),感觉好像只能用它做项目必须得一开始就使用它,而不能中途使用。希望能够自定义的方式使用GORM,不使用它提供的自动迁移,于是记录下来。

需求

现在我突然接收了别人的项目(可能是一个java项目),然后需要用golang实现数据库操作,别人的数据库不能改动,那么我就需要自定义Model一个一个适配。

案例

官网地址:gorm.io/docs/index.…

官网github:github.com/go-gorm/gor…

demo地址:github.com/BuddyXiao/g…

假如说目前已经有了三个表,分别是t_user,t_role和t_user_role,在po包中可以看到相应的结构体。

关联关系

多对多关系:

无法使用预加载的功能特性。

// 查询用户和该用户的所有角色
func TestAssociation(t *testing.T) {
   dao.Init()
   var user = po.User{}
   user.ID = 1563001523807162370
   var roleIds []int
   dao.DB.Model(&po.UserRole{}).Where("user_id = ?", user.ID).Select("role_id").Find(&roleIds)
   var roles []po.Role
   dao.DB.Where("deleted = 0").Find(&orles, roleIds)
   dao.DB.First(&user)
   user.Roles = roles
   //dao.DB.Preload("Roles").Where("deleted = 0").Find(&user) 无法使用预加载
   fmt.Println(user)
}

Clause的使用

这个是GORM用来创建SQL语句的神器。在官方的clause包可以看到许多测试用例。

在钩子函数中实现软删除

这种方式的软删除,在查询是还得加上deleted=0的限制

以下是拼接一个UPDATE的语句:

func (u *User) BeforeDelete(tx *gorm.DB) (err error) {
   clauses := []clause.Interface{
      clause.Update{},
      clause.Set([]clause.Assignment{{Column: clause.Column{Name: "deleted"}, Value: 100}}),
      clause.Where{Exprs: []clause.Expression{clause.Eq{Column: clause.PrimaryColumn, Value: u.ID}}},
   }
   for _, c := range clauses {
      tx.Statement.AddClause(c)
   }
   tx.Statement.Build("UPDATE", "SET", "WHERE")
   fmt.Println(tx.Statement.SQL.String()) // UPDATE `t_user` SET `deleted`=? WHERE `t_user`.`id` = ?
   return
}

测试:这里需要传递user对象,将id传给BeforeDelete函数的接收者

func TestDeleteSimple(t *testing.T) {
   dao.Init()
   id := 1563001523807162373
   var user po.User
   user.ID = id
   result := dao.DB.Delete(&user)
   fmt.Println(result.Statement.SQL.String())
   fmt.Println(result.RowsAffected)
   fmt.Println(result.Error)
}

使用技巧

  1. 查看中间生成的SQL语句
db := dao.DB.Session(&gorm.Session{DryRun: true})
s1 := db.Model(&po.UserRole{}).Where("user_id = ?", user.ID).Select("role_id").Find(&orleIds).Statement
fmt.Println("orleIds:", s1.SQL.String())
// SELECT `role_id` FROM `t_user_role` WHERE user_id = ?

  • 在go结构体与数据库表做映射时,必须要将go结构体中属性字段的Tag标签中加入gorm:"column:xxxx", 不然可能出现查询不到结果的情况。

学习链接

Go语言技巧 - 7.【GORM实战剖析】基本用法和原理解析 - 哔哩哔哩 (bilibili.com)

介绍 - 《GORM 2.0 使用教程(中文文档)》 - 书栈网 · BookStack