Go语言,使用sqlx.StructScan扫描嵌入的结构体 [英] Go language, scanning embeded struct with sqlx.StructScan

查看:3489
本文介绍了Go语言,使用sqlx.StructScan扫描嵌入的结构体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚开始学习Go语言。
我写了以下简单的程序。



这里我试图填充所有书籍和相关的Authers结构。



struct已嵌入 p>

  package main 
import(
fmt
log
time
github.com/jmoiron/sqlx
_github.com/lib/pq


类型Book struct {
ID int
标题字符串
年份int
Bauther Auther`db:auther`
}

类型Auther struct {
ID int
名字字符串
Dob time.Time
}

func main(){
db,err:= sqlx.Open(postgres,host = localhost user = testuser dbname = testdb password = testuser)
如果err!= nil {
log.Fatal(DB Conn error:,err)
}
b $ b if err = db.Ping(); err!= nil {
log.Fatal(DB Ping error:,err)
}
defer db.Close()

rows,err: db.Queryx(Select b。*,a.name from books b left outer join authers on a.ID = b.auther;)
如果err!= nil {
log.Fatal DB Query error:,err)
}
defer rows.Close()

var books [] * Book
for rows.Next b $ b var b =& Book {}
err:= rows.StructScan(b)
如果err!= nil {
log.Fatal(Scan error:
}
books = append(books,b)
}

//打印所有书籍
for _,b:= range books {
fmt.Printf(%v,b)
}
}

但是当我运行它,它给出以下错误

  [samtech @ sam sqlxapp] $ go run main.go 
2016/02/11 18:45:46扫描错误:缺少目标名称名称
退出状态1

我做错了什么?



我也试过在 Book

  Bauther Auther`db:auther,prefix = auth。`

并将查询更改为

  rows, = db.Queryx(Select b。*,auth.name from books b left outer join authers auth on auth.ID = b.auther;)

但不会改变。



EDIT
$ b

经过几次尝试和错误,最后我使它工作。



我必须稍微改变我创建的模型。我改变了Book结构从

  type Book struct {
ID int
标题字符串
年int
Bauther Auther
}



类型Book struct {
ID int // Key
标题字符串
年份int
AutherID int`db: auther`// FKey
Auther
}

工作正常。我做错了,我添加 Bauther 字段为 Auther 。 Sqlx不明白。但是当我添加 Auther 作为匿名嵌入式结构时,问题解决了。



但是它引入了另一个问题: / p>

由于ID字段存在于 Book 以及 Auther 两个结构体。现在ScanStruct正在填充 Book.ID 在所有行中为0.



有什么我可以做,以避免它?

解决方案

这似乎不可能与sqlx目前。有一个开放的问题: https://github.com/jmoiron/sqlx/issues/131



不过不需要使用sqlx就可以这么做:

  package main 

import(
database / sql
fmt
log
time
b $ b _github.com/lib/pq


类型书架{
ID int
标题字符串
年int $ b Bauther Auther
}

类型Auther struct {
ID int
名称字符串
Dob time.Time
}

func main(){
db,err:= sql.Open(postgres,postgres:// localhost / testdb?sslmode = disable)
如果err!= nil {
log.Fatal(DB Conn error:,err)
}

如果err = db.Ping(); err!= nil {
log.Fatal(DB Ping error:,err)
}
defer db.Close()

rows,err: db.Query(Select b.id,b.title,b.year,a.id,a.name,a.dob from books b left outer join authers a on a.ID = b.auther;)
if err!= nil {
log.Fatal(DB Query error:,err)
}
defer rows.Close()

var books [] * Book
for rows.Next(){
var b =& Book {}
如果err:= rows.Scan(& b.ID,& b.T​​itle ,& b.Year,& b.Bauther.ID,& b.Bauther.Name,& b.Bauther.Dob); err!= nil {
log.Fatal(err)
}
books = append(books,b)
}

//打印所有图书
for _,b:=范围书{
fmt.Printf(%v,b)
}
}

基本上你必须明确你的 SELECT 语句中的列,的人。然后你创建你的结构,并扫描到每个元素,其顺序与你的 SELECT 语句中的列相同。


I have just started learning Go language. I wrote following simple program.

Here i am trying to fill struct with all Books and related Authers.

Book struct has embeded Author struct.

package main
import (
    "fmt"
    "log"
    "time"
    "github.com/jmoiron/sqlx"
    _ "github.com/lib/pq"
)

type Book struct {
    ID      int
    Title   string
    Year    int
    Bauther  Auther `db:"auther"`
}

type Auther struct {
    ID      int
    Name    string
    Dob     time.Time
}

func main() {
    db, err := sqlx.Open("postgres", "host=localhost user=testuser dbname=testdb password=testuser")
    if err != nil {
       log.Fatal("DB Conn error: ", err)
    }

    if err = db.Ping(); err != nil {
        log.Fatal("DB Ping error: ", err)
    }
    defer db.Close()

    rows, err := db.Queryx("Select b.*, a.name from books b left outer join authers a on a.ID=b.auther;")
    if err != nil {
        log.Fatal("DB Query error: ", err)
    }
    defer rows.Close()

    var books []*Book
    for rows.Next() {
        var b = &Book{}
        err := rows.StructScan(b)
        if err != nil {
            log.Fatal("Scan error: ", err)
        }
        books = append(books, b)
    }

    // print all books
    for _, b := range books {
        fmt.Printf("%v", b)
    }
}

But when i run it, it is giving following error

[samtech@sam sqlxapp]$ go run main.go
2016/02/11 18:45:46 Scan error: missing destination name name
exit status 1

What i am doing wrong?

I have also tried changing field tag in Book struct to

Bauther  Auther `db:"auther,prefix=auth."`

and change query to

rows, err := db.Queryx("Select b.*, auth.name from books b left outer join authers auth on auth.ID=b.auther;")

But it doesn't make any change.

EDIT

After few try and errors, finally i make it working.

I have to slightly change the Models that i have created. I changed Book struct from

type Book struct {
    ID      int
    Title   string
    Year    int
    Bauther Auther
}

to

type Book struct {
    ID          int                  // Key
    Title       string
    Year        int
    AutherID    int `db:"auther"`   // FKey
    Auther 
}

Now, it is working fine. The mistake i was doing was, i added Bauther field as Auther. Sqlx could not understand it. But when i added Auther as anonymous embedded struct, the problem resolved.

But it introduces another problem :)

As ID field exist in Book as well as in Auther both the structs. Now ScanStruct is filling Book.ID with 0 in all rows.

Is there anything that i can do to avoid it?

解决方案

This doesn't seem possible with sqlx at the moment. There is a open issue for this: https://github.com/jmoiron/sqlx/issues/131

You can however do that easily without using sqlx:

package main

import (
    "database/sql"
    "fmt"
    "log"
    "time"

    _ "github.com/lib/pq"
)

type Book struct {
    ID      int
    Title   string
    Year    int
    Bauther Auther
}

type Auther struct {
    ID   int
    Name string
    Dob  time.Time
}

func main() {
    db, err := sql.Open("postgres", "postgres://localhost/testdb?sslmode=disable")
    if err != nil {
        log.Fatal("DB Conn error: ", err)
    }

    if err = db.Ping(); err != nil {
        log.Fatal("DB Ping error: ", err)
    }
    defer db.Close()

    rows, err := db.Query("Select b.id, b.title, b.year, a.id, a.name, a.dob from books b left outer join authers a on a.ID=b.auther;")
    if err != nil {
        log.Fatal("DB Query error: ", err)
    }
    defer rows.Close()

    var books []*Book
    for rows.Next() {
        var b = &Book{}
        if err := rows.Scan(&b.ID, &b.Title, &b.Year, &b.Bauther.ID, &b.Bauther.Name, &b.Bauther.Dob); err != nil {
            log.Fatal(err)
        }
        books = append(books, b)
    }

    // print all books
    for _, b := range books {
        fmt.Printf("%v", b)
    }
}

Basically you have to be explicit of your columns in your SELECT statement, so that you know the order of them. Then you create your struct and scan into each element with the same order as your columns in your SELECT statement.

这篇关于Go语言,使用sqlx.StructScan扫描嵌入的结构体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆