英文:
Custom scanner for structs in Go
问题
我正在使用Go编写一种类似于REST的API。我有一个遗留的数据库,所以我无法控制字段名、结构或其他任何内容。我正在一个名为datastore的单独包中抽象数据库访问方法。我的代码如下所示(省略了所有的错误处理等):
type Datastore struct {}
type Object struct {
id uint
name string
... 这里还有很多其他字段
}
func (Datastore) ObjectList() {
var objects *[]Object
db, _ := sqlx.Open("postgres", conn_info)
rows, _ := sqlx.Queryx("SELECT * FROM object_table")
defer rows.Close()
for rows.Next() {
var obj Object
rows.Scan(&obj.id, &obj.name)
objects = append(objects, obj)
}
return objects
}
我目前遇到的问题是对象表有很多字段,有些我关心,有些我不关心。有些字段与Object的字段同名,有些则不是。最终,我需要支持大部分字段,但我现在只是在进行概念验证。如果在行中发现的字段多于Scan()函数的参数数量,Scan代码会失败。我可以在查询中列出我要扫描的字段,例如select id, name from object_table
,但是:
- 这会使代码非常丑陋(SQL语句无法正确格式化)
- 这会增加另一个需要编辑的地方,当我想要支持另一个字段时
有没有办法实现一个自定义的扫描器接口,它可以接收rows对象,将其中的一些数据加载到结构体中,并忽略其余的数据?
英文:
I am writing a sort of a REST-like API in Go. The database I have is legacy, so I don't control the field names or the structure or for that matter anything. I am abstracting database access methods in a separate package called datastore. The code I have looks like this (skipping all the error handling etc.)
<pre>
type Datastore struct {}
type Object struct {
id uint
name string
... zillion more fields here
}
func (Datastore) ObjectList() {
var objects *[]Object
db, _ := sqlx.Open("postgres", conn_info)
rows, _ := sqlx.Queryx("SELECT * FROM object_table")
defer rows.Close()
for rows.Next() {
var obj Object
rows.Scan(&obj.id, &obj.name)
objects = append(objects, obj)
}
return objects
}
</pre>
The problem I am currently having is that the object table has dozens and dozens of fields. Some I care about, but some I do not. Some are named the same as Object and some are not. Eventually, I will need to support most of them, but I am working on a proof of concept first. It seems that the Scan code fails if it finds more fields in the row than are present in the arguments for Scan(). I could list the fields I scan for in the query select id, name from object_table
, but
- it makes the code extremely ugly (SQL doesn't get formatted right by gofmt)
- it adds another place I need to edit when I want to support another field
Is there any way to implement a custom scanner interface that would take the rows object, load some data out of it into a struct and ignore the rest?
答案1
得分: 0
你已经在使用sqlx,所以只需要在查询之前使用*DB.Unsafe():
var db *sqlx.DB
// 与内置的方式完全相同
db = sqlx.Open("sqlite3", ":memory:")
var p Person
udb := db.Unsafe()
err = udb.Get(&p, "SELECT * FROM person, place LIMIT 1;")
英文:
You are already using sqlx so just use *DB.Unsafe() before querying :
var db *sqlx.DB
// exactly the same as the built-in
db = sqlx.Open("sqlite3", ":memory:")
var p Person
udb := db.Unsafe()
err = udb.Get(&p, "SELECT * FROM person, place LIMIT 1;")
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论