[Golang]OpenGauss数据库简易orm搭建(四)

这是我参与11月更文挑战的第28天,活动详情查看:2021最后一次更文挑战

前言

经过前几篇文章的铺垫,在Go语言中实现结构体反射实现数据库操作已经开始得心应手起来了,且由于数据修改和之前的数据插入类似,数据删除也有不少共通之处,因此将两个操作合并讲解。

数据修改

很数据插入操作类似,我们需要实现将数据中值为空的数据对应的字段提取出来,先构建一个map对象存储,然后通过字符串拼接的方式构建需要的sql语句,因此在这部分,代码和之前完全一致:

t := reflect.TypeOf(model)
mp := make(map[string]string)
for i := 0; i < t.Elem().NumField(); i++ {
   field := t.Elem().Field(i)
   name := field.Name
   value := reflect.ValueOf(model).Elem().FieldByName(name).String()
   if value == "" {
      continue
   }
   mp[name] = value
}
复制代码

和数据插入不同,我们在执行插入操作是,主键是由我们自己决定的,但是修改和删除操作,需要获取到主键,通过添加WHERE查询条件,才能定位数据,实现修改和删除。

当然,由于之前建表的时候我们已经将主键的信息存在Tags内了,因此我们只需要反射使用field.Tag.Get读取标签,遍历搜索主键名,然后再使用reflect.ValueOf,实现主键值的获取。

此部分代码实现如下:

// getPrimaryKey 获取结构体主键名和对应值
func getPrimaryKey(model interface{}) (name string, value string, err error) {
   // 反射获取主键名和对应值
   t := reflect.TypeOf(model)
   for i := 0; i < t.Elem().NumField(); i++ {
      field := t.Elem().Field(i)
      constraint := field.Tag.Get("constraint")
      if strings.Contains(constraint, "PRIMARY KEY") {
         name = field.Tag.Get("json")
         value = reflect.ValueOf(model).Elem().FieldByName(name).String()
      }
   }
   if name != "" && value != "" {
      return
   }
   err = errors.New("PRIMARY KEY NO FOUND")
   return
}
复制代码

另外,数据修改和数据插入操作一大不同是sql语句结构的不同,因此,在字符串拼接实现上,存在较大差异。

数据修改操作,完整代码实现如下:

name, value, err := getPrimaryKey(model)
if err != nil {
   return err
}
tableName := strings.Split(t.String(), ".")[1]
sql := "UPDATE " + tableName + " SET\n"
tmp := 0
for k, v := range mp {
   sql += fmt.Sprintf("\t%s = '%s'", k, v)
   tmp++
   if tmp != len(mp) {
      sql += ",\n"
   }
}
复制代码

使用方法如下:

err := models.Update(&models.Role{
   Id:           "1",
   Name:         "Admin666",
   Introduction: "管理员666",
})
fmt.Println(err)
复制代码

生成的sql语句:

UPDATE Role SET
    Id = '1',
    Name = 'Admin666',
    Introduction = '管理员666'
WHERE Id = 1;
复制代码

数据删除

数据删除比较简单,一个删除语句如下:

DELETE FROM Role
WHERE id = 1;
复制代码

可以看到,除表名外,我们只需要主键和主键名,就可以实现删除了。

凑巧的是,这两参数,我们在实现上面数据修改的时候已经完成了,因此直接写出代码:

func Delete(model interface{}) error {
   t := reflect.TypeOf(model)
   tableName := strings.Split(t.String(), ".")[1]
   sql := "DELETE FROM " + tableName
   name, value, err := getPrimaryKey(model)
   if err != nil {
      return err
   }
   sql += fmt.Sprintf("\nWHERE %s = %s;", name, value)
   logrus.Debugln(sql)
   _, err = db.Exec(sql)
   return err
}
复制代码

使用方式如下:

err := models.Delete(&models.Role{
   Id:           "1",
})
fmt.Println(err)
复制代码

生成的sql语句就是上面展示的那个。