如何以良好的方式处理SQL空值和JSON?

如何以良好的方式处理SQL空值和JSON?,sql,json,go,Sql,Json,Go,像Int64和String这样的Go类型不能存储空值, 所以我发现我可以用和来做这个 但当我在结构中使用这些时, 并从带有包的结构生成JSON, 然后,格式与使用常规Int64和字符串类型时不同 JSON还有一个附加级别,因为sql.Null***也是一个结构 有没有一个好的解决办法, 或者我不应该在我的SQL数据库中使用null吗?像SQL.NullInt64这样的类型不会对JSON封送或解封送实现任何特殊处理,因此默认规则适用。因为类型是一个结构,所以它作为一个对象进行封送,其字段作为属性

像Int64和String这样的Go类型不能存储空值, 所以我发现我可以用和来做这个

但当我在结构中使用这些时, 并从带有包的结构生成JSON, 然后,格式与使用常规Int64和字符串类型时不同

JSON还有一个附加级别,因为sql.Null***也是一个结构

有没有一个好的解决办法, 或者我不应该在我的SQL数据库中使用null吗?

像SQL.NullInt64这样的类型不会对JSON封送或解封送实现任何特殊处理,因此默认规则适用。因为类型是一个结构,所以它作为一个对象进行封送,其字段作为属性

解决这个问题的一种方法是创建自己的类型,该类型实现json.marshaler/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 {
    // 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
}
如果使用此类型代替sql.NullInt64,则应按预期对其进行编码

您可以在这里测试这个示例:

像sql.NullInt64这样的类型不实现JSON封送或解封送的任何特殊处理,因此默认规则适用。因为类型是一个结构,所以它作为一个对象进行封送,其字段作为属性

解决这个问题的一种方法是创建自己的类型,该类型实现json.marshaler/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 {
    // 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
}
如果使用此类型代替sql.NullInt64,则应按预期对其进行编码

您可以在这里测试这个示例:

如果您使用这个包,就不需要实现任何封送或解封送方法。它是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"` // Optional
}
如果您希望看到使用sqlite、nulls和json的完整Golang Web服务器,您可以咨询。

如果您使用该包,则不需要实现任何封送或解封方法。它是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"` // Optional
}

如果您想看到一个使用sqlite、nulls和json的完整Golang Web服务器,您可以咨询。

您应该解释一下,当我在您的问题中使用常规int64和字符串时,您所说的不是什么意思。您尝试过使用指向ints的指针,是吗?ie:var-anint*int,然后使用&anint如果为null,指针将为nil。可以很好地使用JSON编码。这当然适用于gorp,没有用直接的sql包进行测试,但您应该解释一下,当我在您的问题中使用常规int64和string时,您所说的不是什么意思。您尝试过使用指向Int的指针,是吗?ie:var-anint*int,然后使用&anint如果为null,指针将为nil。可以很好地使用JSON编码。这当然适用于gorp,但还没有用直接的sql包进行测试,这是一个多么伟大的解决方案!非常感谢。也许这是多余的,但有Golang操场来展示这样的东西真是太棒了——真的对语言的采用产生了巨大的影响。谢谢你的回答。谢谢你,伙计!这正是我正在寻找的一个伟大的解决方案!非常感谢。也许这是多余的,但有Golang操场来展示这样的东西真是太棒了——真的对语言的采用产生了巨大的影响。谢谢你的回答。谢谢你,伙计!这正是我要找的这是一个巨大的节省时间。我原以为我必须编写所有的封送处理代码,但这个包工作得非常好。这大大节省了时间。我原以为我必须编写所有封送处理代码,但这个包工作得非常完美。