码迷,mamicode.com
首页 > 数据库 > 详细

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

时间:2017-08-05 18:57:53      阅读:285      评论:0      收藏:0      [点我收藏+]

标签:tin   get   存储   span   return   atoi   dex   结构体   parse   

通用的映射模式

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笔记(1)-数据库查询结果映射至结构体

标签:tin   get   存储   span   return   atoi   dex   结构体   parse   

原文地址:http://www.cnblogs.com/fwdqxl/p/7290961.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!