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


    通用的映射模式

    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
    }
    
    
    
    
    
  • 相关阅读:
    05.九个内置对象
    04.线程面试题-01
    03.反射杂谈
    02.Java动态代理实现与原理分析之静态代理
    01.JDBC技术摘要
    异步请求二
    表单验证(添加数据)
    异步请求(删除json数据)
    异步请求(解析json数据)
    异步请求(获取json数据)
  • 原文地址:https://www.cnblogs.com/fwdqxl/p/7290961.html
Copyright © 2020-2023  润新知