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笔记-数据库查询结果映射至结构体的主要内容,如果未能解决你的问题,请参考以下文章