英文:
golang reflect for sql scan report error
问题
/**
-- name是character varying(64)
CREATE TABLE users
(
id bigint NOT NULL,
no character(24),
identity name,
name name,
head character varying(256),
email character varying(256),
site character varying(256),
create_time timestamp without time zone,
city_id bigint,
timezone jsonb,
update_time timestamp without time zone,
CONSTRAINT user__pk PRIMARY KEY (id)
)
spottly=# SELECT "id", "no", "identity", "name", "head", "email", "site", "create_time", "city_id", "update_time", "timezone" FROM "users" WHERE "email" = 'fixopen@yeah.net' LIMIT 1 OFFSET 0;
id | no | identity | name | head | email | site | create_time | city_id | update_time | timezone
----------------+----+----------+---------+----------------------------------------+------------------+----------------------------+-------------+---------+-------------+----------
95083655397376 | | fixopen | fixopen | /uploader/52e2762edf4e633666000867.png | fixopen@yeah.net | http://spottly.com/fixopen | | | |
(1 row)
*/
package main
import (
"database/sql"
//"errors"
"fmt"
_ "github.com/lib/pq"
"log"
"net/url"
"reflect"
"strings"
"time"
)
type User struct {
Id uint64 json:"id"
No *string json:"no"
Identity string json:"identity"
Name string json:"name"
Head url.URL json:"head"
Email *string json:"email"
Site url.URL json:"site"
Create_time time.Time json:"create-time"
City_id *uint64 json:"city-id"
Update_time time.Time json:"update-time"
Timezone *string json:"timezone"
}
func main() {
connectionString := "host=localhost port=5432 user=postgres dbname=spottly password=123456 sslmode=disable"
db, err := sql.Open("postgres", connectionString)
defer db.Close()
if err != nil {
log.Fatal(err)
}
t := reflect.TypeOf(User{})
//u := reflect.New(t).Elem().Interface()
//fmt.Printf("u is %T, %#v\n", u, u)
resultValuePtr := reflect.New(t)
resultValue := resultValuePtr.Elem()
fieldCount := t.NumField()
fields := make([]reflect.StructField, fieldCount)
for i := 0; i < fieldCount; i++ {
fields[i] = t.Field(i)
}
columns := make([]string, fieldCount)
fieldAddrs := make([]interface{}, fieldCount)
for i := 0; i < fieldCount; i++ {
columns[i] = strings.ToLower(fields[i].Name)
fieldAddrs[i] = resultValue.Field(i).Addr().Interface()
}
columnNames := strings.Join(columns, `","`)
command := `SELECT "` + columnNames + `" FROM "users" WHERE "email" = 'fixopen@yeah.net' LIMIT 1 OFFSET 0`
fmt.Printf("查询命令是 %v\n", command)
// fmt.Printf("meta field is %v\n", fields)
// fmt.Printf("field addr is %#v\n", fieldAddrs)
err = db.QueryRow(command).Scan(fieldAddrs...)
if err == nil {
result := resultValuePtr.Interface()
fmt.Printf("结果是 %#v\n", result)
} else {
fmt.Printf("查询错误是 %v\n", err)
//panic(errors.New("halt"))
}
}
数据库模式和数据显示在注释中。
查询命令是:
SELECT "id", "no", "identity", "name", "head", "email", "site", "create_time", "city_id", "update_time", "timezone" FROM "users" WHERE "email" = 'fixopen@yeah.net' LIMIT 1 OFFSET 0
与注释中相同,此命令使用 psql
执行返回一行数据。
sql Scan 方法执行错误,输出:
查询错误是 sql: Scan error on column index 4: unsupported driver -> Scan pair: []uint8 -> *url.URL
我的 Golang 版本是 go version go1.5.2 darwin/amd64
PostgreSQL 版本是 9.4.2
使用 github.com/lib/pq
访问数据库。
这是数据库驱动程序不支持将字符串列扫描到 url.URL 类型吗?
我该怎么办?
英文:
/**
-- name is character varying(64)
CREATE TABLE users
(
id bigint NOT NULL,
no character(24),
identity name,
name name,
head character varying(256),
email character varying(256),
site character varying(256),
create_time timestamp without time zone,
city_id bigint,
timezone jsonb,
update_time timestamp without time zone,
CONSTRAINT user__pk PRIMARY KEY (id)
)
spottly=# SELECT "id", "no", "identity", "name", "head", "email", "site", "create_time", "city_id", "update_time", "timezone" FROM "users" WHERE "email" = 'fixopen@yeah.net' LIMIT 1 OFFSET 0;
id | no | identity | name | head | email | site | create_time | city_id | update_time | timezone
----------------+----+----------+---------+----------------------------------------+------------------+----------------------------+-------------+---------+-------------+----------
95083655397376 | | fixopen | fixopen | /uploader/52e2762edf4e633666000867.png | fixopen@yeah.net | http://spottly.com/fixopen | | | |
(1 row)
*/
package main
import (
"database/sql"
//"errors"
"fmt"
_ "github.com/lib/pq"
"log"
"net/url"
"reflect"
"strings"
"time"
)
type User struct {
Id uint64 `json:"id"`
No *string `json:"no"`
Identity string `json:"identity"`
Name string `json:"name"`
Head url.URL `json:"head"`
Email *string `json:"email"`
Site url.URL `json:"site"`
Create_time time.Time `json:"create-time"`
City_id *uint64 `json:"city-id"`
Update_time time.Time `json:"update-time"`
Timezone *string `json:"timezone"`
}
func main() {
connectionString := "host=localhost port=5432 user=postgres dbname=spottly password=123456 sslmode=disable"
db, err := sql.Open("postgres", connectionString)
defer db.Close()
if err != nil {
log.Fatal(err)
}
t := reflect.TypeOf(User{})
//u := reflect.New(t).Elem().Interface()
//fmt.Printf("u is %T, %#v\n", u, u)
resultValuePtr := reflect.New(t)
resultValue := resultValuePtr.Elem()
fieldCount := t.NumField()
fields := make([]reflect.StructField, fieldCount)
for i := 0; i < fieldCount; i++ {
fields[i] = t.Field(i)
}
columns := make([]string, fieldCount)
fieldAddrs := make([]interface{}, fieldCount)
for i := 0; i < fieldCount; i++ {
columns[i] = strings.ToLower(fields[i].Name)
fieldAddrs[i] = resultValue.Field(i).Addr().Interface()
}
columnNames := strings.Join(columns, "\", \"")
command := "SELECT \"" + columnNames + "\" FROM \"users\" WHERE \"email\" = 'fixopen@yeah.net' LIMIT 1 OFFSET 0"
fmt.Printf("query command is %v\n", command)
// fmt.Printf("meta field is %v\n", fields)
// fmt.Printf("field addr is %#v\n", fieldAddrs)
err = db.QueryRow(command).Scan(fieldAddrs...)
if err == nil {
result := resultValuePtr.Interface()
fmt.Printf("result is %#v\n", result)
} else {
fmt.Printf("Select one error is %v\n", err)
//panic(errors.New("halt"))
}
}
database schema and data show in comment.
the query command is:
SELECT "id", "no", "identity", "name", "head", "email", "site", "create_time", "city_id", "update_time", "timezone" FROM "users" WHERE "email" = 'fixopen@yeah.net' LIMIT 1 OFFSET 0
same as comment, this command execute with psql
return one row data.
sql Scan method execute error, output:
Select one error is sql: Scan error on column index 4: unsupported driver -> Scan pair: []uint8 -> *url.URL
My golang version is go version go1.5.2 darwin/amd64
PostgreSQL version is 9.4.2
use github.com/lib/pq
access DB.
It's the db driver not support scan string column to url.URL?
what do I can?
答案1
得分: 1
url.URL
没有实现sql.Scanner
,因此无法从数据库中进行扫描。你可以创建一个实现了sql.Scanner
接口的包装类型:
type sqlURL struct { url.URL }
func (su *sqlURL) Scan(v interface{}) error {
u, err := url.Parse(string(v.([]byte)))
if err != nil {
return err
}
*su = sqlURL{*u}
return nil
}
或者将URL单独扫描为字符串,然后进行解析:
var urlStr string
err = db.QueryRow(command).Scan(/* ... */, &urlStr)
// 检查错误
u, err := url.Parse(urlStr)
// 检查错误
user.Site = *u
以上是翻译的内容。
英文:
url.URL
doesn't implement sql.Scanner
, so it cannot be scanned from DB. You can either make a wrapper type that does implement sql.Scanner
:
type sqlURL struct { url.URL }
func (su *sqlURL) Scan(v interface{}) error {
u, err := url.Parse(string(v.([]byte)))
if err != nil {
return err
}
*su = sqlURL{*u}
return nil
}
or scan the URL into a string separately and then parse it:
var urlStr string
err = db.QueryRow(command).Scan(/* ... */, &urlStr)
// check err
u, err := url.Parse(urlStr)
// check err
user.Site = *u
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论