golang笔记-数据库查询结果映射至结构体

Posted 孤独风中一匹狼

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了golang笔记-数据库查询结果映射至结构体相关的知识,希望对你有一定的参考价值。

通用的映射模式

query:="select id,name from user where id=?"

 

//单个结构体
ret:=&Activity{} DbClient().Find(query,activityId).Unique(ret)
//结构体数组
ret:=[]
Activity{}
DbClient().Find(query,activityId).List(&ret)

 

 

1.定义结构体

type Activity struct{
ID int64 `col:"id" json:"id"`
Name string `col:"name" json:"name"`
}

 

2.定义数据库对象

type dao struct {
    data       []map[string]string // 存储数据库查询数据 
    err        error               // 异常
}
var ProKDB *sql.DB

3. 将对象地址传给结构体

func (d *dao) Unique(in interface{}) error {
if len(d.data) > 0 {
return d.mapping(d.data[0], reflect.ValueOf(in))
}
return nil
}
func (d *dao) mapping(m map[string]string, v reflect.Value) error {
t := v.Type()
val := v.Elem()
typ := t.Elem()

if !val.IsValid() {
return errors.New("数据类型不正确")
}

for i := 0; i < val.NumField(); i++ {

value := val.Field(i)
kind := value.Kind()
tag := typ.Field(i).Tag.Get("col")

if len(tag) > 0 {
meta, ok := m[tag]
if !ok {
continue
}

if !value.CanSet() {
return errors.New("结构体字段没有读写权限")
}

if len(meta) == 0 {
continue
}

if kind == reflect.String {
value.SetString(meta)
} else if kind == reflect.Float32 {
f, err := strconv.ParseFloat(meta, 32)
if err != nil {
return err
}
value.SetFloat(f)
} else if kind == reflect.Float64 {
f, err := strconv.ParseFloat(meta, 64)
if err != nil {
return err
}
value.SetFloat(f)
} else if kind == reflect.Int64 {
integer64, err := strconv.ParseInt(meta, 10, 64)
if err != nil {
return err
}
value.SetInt(integer64)
} else if kind == reflect.Int {
integer, err := strconv.Atoi(meta)
if err != nil {
return err
}
value.SetInt(int64(integer))
} else if kind == reflect.Bool {
b, err := strconv.ParseBool(meta)
if err != nil {
return err
}
value.SetBool(b)
} else {
return errors.New("数据库映射存在不识别的数据类型")
}
}
}
return nil
}

// 查询数据

func (d *dao) Find(sql string, args ...interface{}) *dao {
rows, err := ProKDB.Query(sql, args...)
if err != nil {
d.err = err
return d
}

defer rows.Close()
err = d.query(rows)
if err != nil {
d.err = err
}
return d
}

// 映射数据到 map[string]string
func (d *dao) query(rows *sql.Rows) error {

column, err := rows.Columns() //读出查询出的列字段名
if err != nil {
logger.Error(err)
return err
}

values := make([][]byte, len(column)) //values是每个列的值,这里获取到byte里
scans := make([]interface{}, len(column)) //因为每次查询出来的列是不定长的,用len(column)定住当次查询的长度

for i := range values {
scans[i] = &values[i]
}

results := make([]map[string]string, 0) //最后得到的map
for rows.Next() {
if err := rows.Scan(scans...); err != nil {
//query.Scan查询出来的不定长值放到scans[i] = &values[i],也就是每行都放在values里
logger.Error(err)
return err
}

row := make(map[string]string) //每行数据
for k, v := range values {
//每行数据是放在values里面,现在把它挪到row里
key := column[k]
row[key] = string(v)
}
results = append(results, row)
}
d.data = results
return nil
}
// 将对象地址传出去
func (d *dao) Unique(in interface{}) error {
if len(d.data) > 0 {
return d.mapping(d.data[0], reflect.ValueOf(in))
}
return nil
}
func (d *dao) List(in interface{}) error {
    if d.err != nil {
        return d.err
    }

    length := len(d.data)

    if length > 0 {
        v := reflect.ValueOf(in).Elem()
        newv := reflect.MakeSlice(v.Type(), 0, length)
        v.Set(newv)
        v.SetLen(length)

        index := 0
        for i := 0; i < length; i++ {
            k := v.Type().Elem().Elem()
            newObj := reflect.New(k)
            err := d.mapping(d.data[i], newObj)
            if err != nil {
                return err
            }
            v.Index(index).Set(newObj)
            index++
        }
        v.SetLen(index)
    }
    return nil
}

 


 

以上是关于golang笔记-数据库查询结果映射至结构体的主要内容,如果未能解决你的问题,请参考以下文章

golang 结构体笔记

Golang中结构体Struct

Golang中结构体Struct

Golang中结构体Struct

golang学习笔记4——结构体

Golang入门到项目实战 golang结构体指针