1. 程式人生 > >golang筆記(1)-數據庫查詢結果映射至結構體

golang筆記(1)-數據庫查詢結果映射至結構體

tint 地址 style 定義數據 range con clas num end

通用的映射模式

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)-數據庫查詢結果映射至結構體