英文:
Combine row.Scan and rows.Scan interfaces in go?
问题
我有两个针对特定表的查询 - 一个用于检索单个项目,另一个用于返回列表。第一个查询使用 sql.DB.QueryRow
,因为它只需要检索一行数据,而第二个查询使用 sql.DB.Query
来返回多个不同的结果。
问题是序列化需要一些工作,我希望通过一个单一的方法来扫描数据库行并将其读入 Go 类型,以减少重复代码。我的代码目前如下所示:
// 一种类型,与其数据库表示形式有很大差异,并且需要一些序列化工作。
type Foo struct {
Baz *Baz
Board [8][8]int
}
// 根据 id 获取一个 foo
func GetFoo(id int) {
row := db.QueryRow("select * from foo where id = ?", id)
// 与下面的代码重复...
var foo Foo
row.Scan(&foo.blah, &foo.etc)
// 进行更多工作以序列化类型...
}
// 获取所有的 foo
func GetFooes() {
rows, err := db.Query("select * from foo")
for rows.Next() {
// 与上面的代码重复...
var foo Foo
rows.Scan(&foo.blah, &foo.etc)
// 进行更多工作以序列化类型...
}
}
然而,组合 row.Scan
和 rows.Scan
有点棘手。我认为可以使用类似以下的方法:
func serializeFoo(scanner sql.Scanner) (*Foo, error) {
}
不过,sql.Scanner
接口只接受单个 (value interface{})
,而不是 (...value interface{})
的列表。
在这里有什么建议吗?另一个解决方案是将单个的 QueryRow
调用转换为 db.Query
。
英文:
I have two queries against a particular table in Go - one to retrieve a single item and the other to return a list. The first one uses sql.DB.QueryRow
because it only needs to retrieve a single row, and the second one uses sql.DB.Query
to return a few different results.
The problem is that serialization takes some work and I'd like to DRY it up by having a single method that scans from a database row and reads it into a Go type. My code right now looks like:
// Some type which varies considerably from its DB representation, and takes some effort to serialize.
type Foo struct {
Baz *Baz
Board [8][8]int
}
// Get one foo by its id
func GetFoo(id int) {
row := db.QueryRow("select * from foo where id = ?", id)
// Work that's duplicated from below...
var foo Foo
row.Scan(&foo.blah, &foo.etc)
// Do more work to serialize the type...
}
// Get all of the fooes
func GetFooes() {
rows, err := db.Query("select * from foo")
for rows.Next() {
// Work that's duplicated from above...
var foo Foo
rows.Scan(&foo.blah, &foo.etc)
// Do more work to serialize the type...
}
}
However combining row.Scan and rows.Scan is proving to be a little tricky. I thought I could use something like:
func serializeFoo(scanner sql.Scanner) (*Foo, error) {
}
though sql.Scanner takes a single (value interface{})
and not a list of (...value interface{})
.
Any advice here? Another solution would be to convert the single QueryRow
call into a db.Query
.
答案1
得分: 2
db.QueryRow是一个方便的函数。除非它能节省打字/代码复杂性,否则没有理由使用它。在这种情况下,它并没有节省,所以我建议你只使用db.Query。
更多详情请参考http://golang.org/src/pkg/database/sql/sql.go?s=25740:25802#L966
正如你所提到的,Row和Rows都没有实现Scanner接口。Scanner接口用于可变参数扫描函数的参数。
如果你想要一个允许Row或Rows的参数,你需要自己创建一个接口。例如:
func serializeFoo(scanner interface{Scan(dest ...interface{}) error}) (*Foo, error) {
}
英文:
db.QueryRow is a convenience function. There is no reason to use it unless it will save on typing/code-complexity. In this case, it doesn't so I recommend you just use db.Query.
See http://golang.org/src/pkg/database/sql/sql.go?s=25740:25802#L966 for more details
As you mentioned, neither Row nor Rows implement the Scanner interface. Scanner is used for arguments of the variatic scan functions.
If you want to have a parameter that allows either Row or Rows, you need to make your own interface For example:
func serializeFoo(scanner interface{Scan(dest ...interface{}) error}) (*Foo, error) {
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论