如何使用 sqlx 扫描到嵌套结构?
How to scan into nested structs with sqlx?
假设我有两个模型,
type Customer struct {
Id int `json:"id" db:"id"`
Name string `json:"name" db:"name"`
Address Address `json:"adress"`
}
type Address struct {
Street string `json:"street" db:"street"`
City string `json:"city" db:"city"`
}
// ...
customer := models.Customer{}
err := db.Get(&customer , `select * from users where id= and name=`, id, name)
但是这次扫描会抛出一个错误:missing destination name street in *models.Customer
我做错了什么吗?如您所见,我已经更新了值对应的数据库。我仔细检查了一下,所以区分大小写应该不是问题。
还是不能使用 https://github.com/jmoiron/sqlx?
我可以在文档中看到它,但仍然无法弄清楚如何解决它。
http://jmoiron.github.io/sqlx/#advancedScanning
users
table 声明为:
CREATE TABLE `users` (
`id` varchar(256) NOT NULL,
`name` varchar(150) NOT NULL,
`street` varchar(150) NOT NULL,
`city` varchar(150) NOT NULL,
)
very link you posted 为您提供了有关如何执行此操作的提示:
StructScan is deceptively sophisticated. It supports embedded structs, and assigns to fields using the same precedence rules that Go uses for embedded attribute and method access
因此,根据您的数据库架构,您可以简单地将 Address
嵌入 Customer
:
type Customer struct {
Id int `json:"id" db:"id"`
Name string `json:"name" db:"name"`
Address
}
在您的原始代码中,Address
是一个字段 ,它有自己的 db
标记。这是不正确的,顺便说一句,您的模式根本没有 address
列。(您似乎从代码片段中编辑了它)
通过将结构嵌入到 Customer
中,包含标签的 Address
字段被提升到 Customer
中,并且 sqlx
将能够从您的查询结果中填充它们。
警告:嵌入该字段也会使任何 JSON 编组的输出变平。它将变成:
{
"id": 1,
"name": "foo",
"street": "bar",
"city": "baz"
}
如果您想将 street
和 city
放入 JSON address
对象中,作为基于原始结构标签的对象,最简单的方法可能是重新映射DB 结构为您的原始类型。
您也可以将查询结果扫描成map[string]interface{}
,但您必须小心how Postgres data types are represented in Go。
我遇到了同样的问题,想出了一个比@blackgreen 的解决方案更优雅的解决方案。
他是对的,最简单的方法是嵌入对象,但我是在一个临时对象中做的,而不是让原来的对象变得更乱。
然后添加一个函数将临时(平面)对象转换为真实(嵌套)对象。
type Customer struct {
Id int `json:"id" db:"id"`
Name string `json:"name" db:"name"`
Address Address `json:"adress"`
}
type Address struct {
Street string `json:"street" db:"street"`
City string `json:"city" db:"city"`
}
type tempCustomer struct {
Customer
Address
}
func (c *tempCustomer) ToCustomer() Customer {
customer := c.Customer
customer.Address = c.Address
return customer
}
现在您可以扫描到 tempCustomer 并在 return 之前简单地调用 tempCustomer.ToCustomer。这可以让您的 JSON 保持干净,并且不需要自定义扫描功能。
假设我有两个模型,
type Customer struct {
Id int `json:"id" db:"id"`
Name string `json:"name" db:"name"`
Address Address `json:"adress"`
}
type Address struct {
Street string `json:"street" db:"street"`
City string `json:"city" db:"city"`
}
// ...
customer := models.Customer{}
err := db.Get(&customer , `select * from users where id= and name=`, id, name)
但是这次扫描会抛出一个错误:missing destination name street in *models.Customer
我做错了什么吗?如您所见,我已经更新了值对应的数据库。我仔细检查了一下,所以区分大小写应该不是问题。 还是不能使用 https://github.com/jmoiron/sqlx?
我可以在文档中看到它,但仍然无法弄清楚如何解决它。 http://jmoiron.github.io/sqlx/#advancedScanning
users
table 声明为:
CREATE TABLE `users` (
`id` varchar(256) NOT NULL,
`name` varchar(150) NOT NULL,
`street` varchar(150) NOT NULL,
`city` varchar(150) NOT NULL,
)
very link you posted 为您提供了有关如何执行此操作的提示:
StructScan is deceptively sophisticated. It supports embedded structs, and assigns to fields using the same precedence rules that Go uses for embedded attribute and method access
因此,根据您的数据库架构,您可以简单地将 Address
嵌入 Customer
:
type Customer struct {
Id int `json:"id" db:"id"`
Name string `json:"name" db:"name"`
Address
}
在您的原始代码中,Address
是一个字段 ,它有自己的 (您似乎从代码片段中编辑了它)db
标记。这是不正确的,顺便说一句,您的模式根本没有 address
列。
通过将结构嵌入到 Customer
中,包含标签的 Address
字段被提升到 Customer
中,并且 sqlx
将能够从您的查询结果中填充它们。
警告:嵌入该字段也会使任何 JSON 编组的输出变平。它将变成:
{
"id": 1,
"name": "foo",
"street": "bar",
"city": "baz"
}
如果您想将 street
和 city
放入 JSON address
对象中,作为基于原始结构标签的对象,最简单的方法可能是重新映射DB 结构为您的原始类型。
您也可以将查询结果扫描成map[string]interface{}
,但您必须小心how Postgres data types are represented in Go。
我遇到了同样的问题,想出了一个比@blackgreen 的解决方案更优雅的解决方案。
他是对的,最简单的方法是嵌入对象,但我是在一个临时对象中做的,而不是让原来的对象变得更乱。
然后添加一个函数将临时(平面)对象转换为真实(嵌套)对象。
type Customer struct {
Id int `json:"id" db:"id"`
Name string `json:"name" db:"name"`
Address Address `json:"adress"`
}
type Address struct {
Street string `json:"street" db:"street"`
City string `json:"city" db:"city"`
}
type tempCustomer struct {
Customer
Address
}
func (c *tempCustomer) ToCustomer() Customer {
customer := c.Customer
customer.Address = c.Address
return customer
}
现在您可以扫描到 tempCustomer 并在 return 之前简单地调用 tempCustomer.ToCustomer。这可以让您的 JSON 保持干净,并且不需要自定义扫描功能。