[英]How do you marshal a sql.NullString such that the output is flattened to give just the value in go?
Given a go struct给定一个 go 结构
type Company struct {
ID int `json:"id"`
Abn sql.NullString `json:"abn,string"`
}
when marshalled with something like this当用这样的东西编组时
company := &Company{}
company.ID = 68
company.Abn = "SomeABN"
result, err := json.Marshal(company)
the result is结果是
{
"id": "68",
"abn": {
"String": "SomeABN",
"Valid": true
}
}
The result desired is想要的结果是
{
"id": "68",
"abn": "SomeABN"
}
I've tried explicitly stating that Abn is a string.我试过明确说明 Abn 是一个字符串。
Abn sql.NullString `json:"abn,string"`
which did not change the result.这并没有改变结果。
How do you marshal a sql.NullString such that the output is flattened to give just the value in go?您如何编组 sql.NullString 以使 output 展平以仅给出 go 中的值?
EDIT编辑
Something like I ended up with after reading the answers from https://stackoverflow.com/users/8256506/nilsocket and https://stackoverflow.com/users/965900/mkopriva在阅读https://stackoverflow.com/users/8256506/nilsocket和https://stackoverflow.com/users/965900/mkopriva的答案后,我得到了类似的结果
package main
import (
"database/sql"
"encoding/json"
"reflect"
//"github.com/lib/pq"
)
/*
https://medium.com/aubergine-solutions/how-i-handled-null-possible-values-from-database-rows-in-golang-521fb0ee267
*/
type NullString sql.NullString
func (x *NullString) MarshalJSON() ([]byte, error) {
if !x.Valid {
x.Valid = true
x.String = ""
//return []byte("null"), nil
}
return json.Marshal(x.String)
}
// Scan implements the Scanner interface for NullString
func (ns *NullString) Scan(value interface{}) error {
var s sql.NullString
if err := s.Scan(value); err != nil {
return err
}
// if nil then make Valid false
if reflect.TypeOf(value) == nil {
*ns = NullString{s.String, false}
} else {
*ns = NullString{s.String, true}
}
return nil
}
type Company struct {
ID int `json:"id"`
Abn NullString `json:"abn"`
}
You cannot, at least not using just sql.NullString
and encoding/json
.你不能,至少不能只使用
sql.NullString
和encoding/json
。
What you can do is to declare a custom type that embeds sql.NullString
and have that custom type implement the json.Marshaler
interface.您可以做的是声明一个嵌入
sql.NullString
的自定义类型,并让该自定义类型实现json.Marshaler
接口。
type MyNullString struct {
sql.NullString
}
func (s MyNullString) MarshalJSON() ([]byte, error) {
if s.Valid {
return json.Marshal(s.String)
}
return []byte(`null`), nil
}
type Company struct {
ID int `json:"id"`
Abn MyNullString `json:"abn,string"`
}
https://play.golang.org/p/Ak_D6QgIzLb https://play.golang.org/p/Ak_D6QgIzLb
Here is the code,这是代码,
package main
import (
"database/sql"
"encoding/json"
"fmt"
"log"
)
//Company details
type Company struct {
ID int `json:"id"`
Abn NullString `json:"abn"`
}
//NullString is a wrapper around sql.NullString
type NullString sql.NullString
//MarshalJSON method is called by json.Marshal,
//whenever it is of type NullString
func (x *NullString) MarshalJSON() ([]byte, error) {
if !x.Valid {
return []byte("null"), nil
}
return json.Marshal(x.String)
}
func main() {
company := &Company{}
company.ID = 68
//create new NullString value
nStr := sql.NullString{String: "hello", Valid: true}
//cast it
company.Abn = NullString(nStr)
result, err := json.Marshal(company)
if err != nil {
log.Println(err)
}
fmt.Println(string(result))
}
Here is the blog post which explains it in detail. 这是详细解释它的博客文章。
The question suggests that you want to expose your database structure as JSON (presumably REST-ish) API.该问题表明您希望将数据库结构公开为 JSON(大概是 REST-ish)API。 Unless the project is going to have a short lifespan or the logic layer is trivial, such an approach is considered an antipattern.
除非项目的生命周期很短或逻辑层是微不足道的,否则这种方法被认为是反模式。 The internals (database structure) become coupled with the external interface (API) and may result in a high cost of making a change.
内部(数据库结构)与外部接口 (API) 耦合在一起,可能会导致进行更改的成本很高。
I'm attaching some reads as Google is full of tutorials on how to do the opposite:我附上了一些读物,因为谷歌有很多关于如何做相反的教程:
https://lostechies.com/jimmybogard/2016/05/12/entities-arent-resources-resources-arent-representations/ https://lostechies.com/jimmybogard/2016/05/12/entities-arent-resources-resources-arent-representations/
https://thorben-janssen.com/dont-expose-entities-in-api/ https://thorben-janssen.com/dont-expose-entities-in-api/
Another option is to use *string
instead of sql.NullString
另一种选择是使用
*string
代替sql.NullString
type Company struct {
ID int `json:"id"`
Abn *string `json:"abn"`
}
Now you may ask yourself what is the Difference between *string and sql.NullString现在你可能会问自己*string 和 sql.NullString 有什么区别
There's no effective difference.
没有有效的区别。 We thought people might want to use NullString because it is so common and perhaps expresses the intent more clearly than *string.
我们认为人们可能想要使用 NullString,因为它很常见,并且可能比 *string 更清楚地表达了意图。 But either will work.
但两者都行。 -- Russ Cox https://groups.google.com/g/golang-nuts/c/vOTFu2SMNeA/m/GB5v3JPSsicJ
-- 拉斯考克斯https://groups.google.com/g/golang-nuts/c/vOTFu2SMNeA/m/GB5v3JPSsicJ
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.