亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Golang通用數據庫單條記錄轉json

Golang通用數據庫單條記錄轉json

Go
倚天杖 2023-05-15 15:32:50
我想從數據庫中檢索記錄并將其編組為 json。我有大約 30 個不同的表,所以我想要適用于所有這些表的通用函數。我使用 xorm 進行數據庫訪問。我設法創建了檢索數據的 DRY 函數,這主要歸功于這個問答這有效,可以將所有記錄編組為 json:type user struct {   Id   int64  `json:"id"`   Name string `json:"name"`}// type post// etc.type tableRecord struct {    PrimaryKey string    Data       interface{}}var ListOfTables = map[string]tableRecord{    "users":{"id", &[]user{}},  // type user is struct for xorm with json annotation    //"posts":{"post_id", &[]post{}},    // etc.. }for tableName, rec := range ListOfTables {    err := xorm.Find(rec.Data)    if err != nil {        log.Print(err)    }    out, err := json.Marshal(rec.Data)    if err != nil {        log.Print(err)    }    log.Print(string(out)) // this yields json array}但是,我很難將單個記錄編組為 json。我四處尋找迭代 interface{} 的方法,它包含一個切片,找到了這個和類似的主題。試過:switch reflect.TypeOf(reflect.ValueOf(rec.Data).Elem().Interface()).Kind() {case reflect.Slice:    s := reflect.ValueOf(reflect.ValueOf(rec.Data).Elem().Interface())    for i := 0; i < s.Len(); i++ {        entry := s.Index(i)        log.Printf("%v\n", entry) // prints {1 John Doe}        // log.Print(reflect.ValueOf(entry))        data, err := json.MarshalIndent(entry, " ", "  ")        if err != nil {            log.Print(err)        }        log.Println(string(data)) // prints {} empty    }}  當然,如果我指定它rec.Data是*[]user有效的,那么我將不得不為每個表重寫這樣的代碼,這不是我所追求的。switch t := rec.Data.(type) {case *[]user:    for _, entry := range *t {        // log.Printf("loop %v", entry)        data, err := json.MarshalIndent(entry, " ", "  ")        if err != nil {            log.Print(err)        }        log.Println(string(data)) // yields needed json for single record    }}或者也許有一種完全不同的、更好的方法來解決這個問題——數據庫的任何記錄到 json。
查看完整描述

1 回答

?
慕標琳琳

TA貢獻1830條經驗 獲得超9個贊

因此,正如我在評論中提到的,如果您希望能夠從字段中獲取單個元素,最簡單的方法tableRecord.Data就是將字段類型更改為實際類型:


type tableRecord struct {

    PrimaryKey string

    Data       []interface{} // slice of whatever

}

這樣,你可以寫一些非常通用的東西:


for tbl, record := range records {

    fmt.Printf("First record from table %s\n", tbl)

    b, _ := json.MarshalIndent(record[0], " ", "  ")

    fmt.Println(string(b))

    fmt.Prinln("other records...")

    b, _ = json.MarshalIndend(record[1:], " ", "  ")

    fmt.Println(string(b))

}

不過,如果我是你,我會考慮在我的數據庫類型中實現一個接口。類似的東西:


type DBType interface {

    PrimaryKey() string

    TableName() string // xorm can use this to get the table name

    Slice() []DBType // can return []user or whatever

}

所以你真的不需要tableRecord類型了,可以像這樣使用 var:


listOfTables := []DBType{user{}, ...}

for _, tbl := range listOfTables {

    data := tbl.Slice()

    // find data here

    fmt.Printf("First record from table %s\n", tbl.TableName())

    b, _ := json.MarshalIndent(data[0], " ", "  ")

    fmt.Println(string(b))

    fmt.Prinln("other records...")

    b, _ = json.MarshalIndend(data[1:], " ", "  ")

    fmt.Println(string(b))

}

所以 TL;DR 我的回答/評論中缺少的內容:


[]user{}從 type (or []DBTable) to 的轉換[]interface{}不起作用,因為您不能在單個表達式中轉換切片中的所有元素。您必須創建第二個類型切片[]interface{}并像這樣復制值:


slice := userVar.Slice() data := make([]interface{}, len(slice)) for i := range slice { data[i] = slice[i] // 復制類型到 interface{} slice } 返回表記錄{userVar.PrimaryKey(), 數據}


我已經創建了一個小的工作示例來說明如何使用上述接口。


演示

為避免太多混亂,您可以更改Slicefunc 以[]interface{}立即返回 a:


func(v T) Slice() []interface{

    return []interface{

        &T{},

    }

}

你的實施有什么問題Slice是你有這樣的事情:


func (u *user) Slice() []DBTable {

    u = &user{} // you're re-assigning the receiver, losing all state!

    return []DBTable{u}

}

接收器是指針類型,因此您所做的任何重新分配都會影響調用 func 的變量。那不是一個好主意。只使用值接收器,或者,如果你想確保接口只在指針變量上實現(一個常見的技巧,例如 gRPC 使用的)是像這樣實現函數:


func(*user) Slice() []DBTable{

    return []DBTable{&user{}}

}

pb.go這個技巧的一個很好的例子可以在使用協議緩沖區時生成的文件中找到。消息類型將具有如下功能:


func(*MsgType) ProtoMessage() {}


查看完整回答
反對 回復 2023-05-15
  • 1 回答
  • 0 關注
  • 178 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號