这是我参与11月更文挑战的第27天,活动详情查看:2021最后一次更文挑战」
前言
上文中,实现了单行数据的查询操作,下面将实现另外一个CURD中另外一个常用操作——数据插入。这改部分采用自顶向下的方式进行说明,从最终调用推到到sql语句生成。
一、使用Insert函数
r := &models.Role {
Name: "Admin",
Introduction: "管理员",
}
err := models.Insert(r)
if err != nil {
fmt.Println(err)
}
复制代码
我们的最终目的就是构建这样一个Insert函数,将我们之前创建的数据库结构体对象此函数实现数据插入数据库的操作,且返回可能出现的错误。
二、编写Insert函数
Insert()函数分为两个部分,一是生成sql语句,二是将sql语句交付数据库执行并捕获错误,其中的重难点在于前者。
下面是一个简单的插入函数,是我们上面Insert函数想要达到的效果(其中主键id由serial数据类型实现自增):
INSERT INTO Role(Name,Introduction)
VALUES ('Admin','管理员')
复制代码
看过前面两文应该已经知道,这里我们需要使用反射reflect.TypeOf()提取出Role对象的所有字段。
但是,仅仅这样是不够的,因为很多时候Role对象内部分字段值为空,表示用户不希望对这些字段进行赋值。
由于对象值的获取是使用reflect.ValueOf()存放的,因此我们需要在读取到值后做进一步的判断,放弃空值字段。
而字段和值恰好是一一对应的关系,可使用map很方便的进行存储,并在后续过程中用于拼接sql语句。
三、交付执行sql语句
字符串拼接这块比较简单(但是要主要行结尾逗号需匹配),就不展开了,最后使用db.Exec(sql)将sql语句交付数据库即可实现插入操作。
四、完整代码实现
// Insert 插入
func Insert(model interface{}) error {
// 把存在的字段插入
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
}
tableName := strings.Split(t.String(), ".")[1]
var kStr string
var vStr string
for k, v := range mp {
kStr += k + ","
vStr += "'" + v + "',"
}
kStr = kStr[:len(kStr)-1]
vStr = vStr[:len(vStr)-1]
sql := fmt.Sprintf("INSERT INTO %s(%s)\nVALUES (%s)", tableName, kStr, vStr)
logrus.Debugln(sql)
_, err := db.Exec(sql)
return err
}
复制代码




近期评论