首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Golang通用数据库单记录到json

Golang通用数据库单记录到json
EN

Stack Overflow用户
提问于 2018-12-14 10:19:16
回答 1查看 460关注 0票数 0

我想从数据库中检索记录,然后把它们发送给json。我有大约30个不同的表,所以我希望泛型函数能够与所有这些表和任何一个表一起工作。我使用xorm进行数据库访问。

我已经成功地创建了检索数据的干函数,主要归功于这个问答

此工作,可以将所有记录编组到json:

代码语言:javascript
复制
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。我一直在寻找迭代一个包含片、找到这个和类似主题的接口{}的方法。试过:

代码语言:javascript
复制
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,那么它可以工作,但是我必须为每个表重写这样的代码,这不是我想要的。

代码语言:javascript
复制
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的记录。

更新现在的问题是,Xorm期望结构吗?我将不得不阅读xorm的可能性和限制。

代码语言:javascript
复制
slice := record.Slice()
log.Print(reflect.TypeOf(slice))

err = env.hxo.In(record.PrimaryKey(), insertIds).Find(slice) // or &slice
if err != nil {
    log.Print(err) // Table not found
}

// this works
var slice2 []*user
err = env.hxo.In(record.PrimaryKey(), insertIds).Find(&slice2)
if err != nil {
    log.Print(err) // 
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-12-14 11:58:32

因此,正如我在注释中提到的,如果您想从tableRecord.Data字段中获取单个元素,最简单的方法就是将字段类型更改为实际情况:

代码语言:javascript
复制
type tableRecord struct {
    PrimaryKey string
    Data       []interface{} // slice of whatever
}

这样,您就可以编写一些非常通用的东西:

代码语言:javascript
复制
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))
}

但是,如果我是您,我会考虑在我的DB类型中实现一个接口。与…有关的东西:

代码语言:javascript
复制
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:

代码语言:javascript
复制
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{} (或[]DBTable)到[]interface{}的转换不起作用,因为您不能在一个表达式中将所有元素转换成一个片段。您必须创建第二个[]interface{}类型的片段,并复制如下所示的值: := userVar.Slice() data := make([]接口{},len( := ))用于I:=范围片{ datai =样片//复制类型到接口{}:=}返回tableRecord{userVar.PrimaryKey(),数据}

我已经创建了一个关于如何使用上面描述的接口的小示例。

演示

为了避免太多的混乱,您可以更改Slice功能,立即返回一个[]interface{}

代码语言:javascript
复制
func(v T) Slice() []interface{
    return []interface{
        &T{},
    }
}

实现Slice的错误之处在于,您有这样的东西:

代码语言:javascript
复制
func (u *user) Slice() []DBTable {
    u = &user{} // you're re-assigning the receiver, losing all state!
    return []DBTable{u}
}

接收器是一个指针类型,所以您正在进行的任何重新分配都将影响调用func的变量。这不是个好主意。只需使用值接收器,或者,如果您想确保接口只在指针变量上实现(例如,gRPC使用的一个常见技巧)就是这样实现该函数:

代码语言:javascript
复制
func(*user) Slice() []DBTable{
    return []DBTable{&user{}}
}

在使用协议缓冲区时,可以在生成的pb.go文件中找到这个技巧的一个很好的例子。消息类型将具有如下函数:

代码语言:javascript
复制
func(*MsgType) ProtoMessage() {}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53777722

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档