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
}
 
         

 

 
        

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM