英文:
How can I work with SQL NULL values and JSON in a good way?
问题
Go类型如Int64
和String
不能存储空值,所以我发现我可以使用sql.NullInt64和sql.NullString来处理这个问题。
但是当我在结构体中使用这些类型,并使用json包从结构体生成JSON时,生成的JSON格式与使用常规的Int64
和String
类型时不同。
这是因为sql.Null***
也是一个结构体,所以JSON多了一层结构。
有没有好的解决方法,或者我应该在我的SQL数据库中不使用NULL值?
英文:
Go types like Int64
and String
cannot store null values,
so I found I could use sql.NullInt64 and sql.NullString for this.
But when I use these in a Struct,
and generate JSON from the Struct with the json package,
then the format is different to when I use regular Int64
and String
types.
The JSON has an additional level because the sql.Null*** is also a Struct.
Is there a good workaround for this,
or should I not use NULLs in my SQL database?
答案1
得分: 79
sql.NullInt64
这样的类型在JSON编组或解组时不实现任何特殊处理,因此适用默认规则。由于该类型是一个结构体,它会被编组为一个带有字段作为属性的对象。
解决这个问题的一种方法是创建一个自己的类型,实现json.Marshaller
/json.Unmarshaler
接口。通过嵌入sql.NullInt64
类型,我们可以免费获得SQL方法。代码如下:
type JsonNullInt64 struct {
sql.NullInt64
}
func (v JsonNullInt64) MarshalJSON() ([]byte, error) {
if v.Valid {
return json.Marshal(v.Int64)
} else {
return json.Marshal(nil)
}
}
func (v *JsonNullInt64) UnmarshalJSON(data []byte) error {
// 将解组到指针可以让我们检测到null
var x *int64
if err := json.Unmarshal(data, &x); err != nil {
return err
}
if x != nil {
v.Valid = true
v.Int64 = *x
} else {
v.Valid = false
}
return nil
}
如果你在代码中使用这个类型来替代sql.NullInt64
,它应该会按照你的期望进行编码。
你可以在这里测试这个示例:http://play.golang.org/p/zFESxLcd-c
英文:
Types like sql.NullInt64
do not implement any special handling for JSON marshaling or unmarshaling, so the default rules apply. Since the type is a struct, it gets marshalled as an object with its fields as attributes.
One way to work around this is to create your own type that implements the json.Marshaller
/ json.Unmarshaler
interfaces. By embedding the sql.NullInt64
type, we get the SQL methods for free. Something like this:
type JsonNullInt64 struct {
sql.NullInt64
}
func (v JsonNullInt64) MarshalJSON() ([]byte, error) {
if v.Valid {
return json.Marshal(v.Int64)
} else {
return json.Marshal(nil)
}
}
func (v *JsonNullInt64) UnmarshalJSON(data []byte) error {
// Unmarshalling into a pointer will let us detect null
var x *int64
if err := json.Unmarshal(data, &x); err != nil {
return err
}
if x != nil {
v.Valid = true
v.Int64 = *x
} else {
v.Valid = false
}
return nil
}
If you use this type in place of sql.NullInt64
, it should be encoded as you expect.
You can test this example here: http://play.golang.org/p/zFESxLcd-c
答案2
得分: 44
如果您使用 null.v3 包,您将不需要实现任何 marshal 或 unmarshal 方法。它是 sql.Null 结构的超集,可能是您想要的。
package main
import "gopkg.in/guregu/null.v3"
type Person struct {
Name string `json:"id"`
Age int `json:"age"`
NickName null.String `json:"nickname"` // 可选
}
如果您想查看一个完整的使用 sqlite、nulls 和 json 的 Golang web 服务器,您可以参考 这个 gist。
英文:
If you use the null.v3 package, you won't need to implement any of the marshal or unmarshal methods. It's a superset of the sql.Null structs and is probably what you want.
package main
import "gopkg.in/guregu/null.v3"
type Person struct {
Name string `json:"id"`
Age int `json:"age"`
NickName null.String `json:"nickname"` // Optional
}
If you'd like to see a full Golang webserver that uses sqlite, nulls, and json you can consult this gist.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论