Go语言中将SQL Server查询结果序列化为目标JSON格式的问题
解决Go中sql.NullXXX类型JSON序列化格式问题
问题背景
从SQL Server的testGo表查询数据并映射到TrnVmSeries结构体后,使用标准库json.Marshal序列化时,sql.NullString、sql.NullBool等类型会输出包含Valid和对应值的嵌套结构,不符合预期的扁平化格式(有效值输出实际值,无效值输出null)。
当前结构体定义:
type TrnVmSeries struct { VmCode sql.NullString IsHidden sql.NullBool Cores sql.NullInt32 Ram sql.NullFloat64 }
当前序列化输出:
[ { "VmCode": { "String":"", "Valid":false }, "IsHidden":{ "Bool":false, "Valid":true }, "Cores":{ "Int32":0, "Valid":true }, "Ram": { "Float64":10, "Valid":true } } ]
预期输出:
[ { "VmCode": null, "IsHidden": false, "Cores": 0, "Ram": 10 } ]
解决方案:实现自定义JSON序列化方法
给TrnVmSeries结构体实现json.Marshaler接口,手动处理每个sql.NullXXX字段的序列化逻辑:
方式一:使用匿名结构体覆盖字段
import ( "database/sql" "encoding/json" ) type TrnVmSeries struct { VmCode sql.NullString IsHidden sql.NullBool Cores sql.NullInt32 Ram sql.NullFloat64 } // MarshalJSON 自定义序列化方法 func (t TrnVmSeries) MarshalJSON() ([]byte, error) { type Alias TrnVmSeries return json.Marshal(&struct { VmCode interface{} `json:"VmCode"` Alias }{ VmCode: t.VmCode.Valid ? t.VmCode.String : nil, Alias: (Alias)(t), IsHidden: t.IsHidden.Bool, Cores: t.Cores.Int32, Ram: t.Ram.Float64, }) }
方式二:使用临时Map构建输出
func (t TrnVmSeries) MarshalJSON() ([]byte, error) { data := make(map[string]interface{}) if t.VmCode.Valid { data["VmCode"] = t.VmCode.String } else { data["VmCode"] = nil } data["IsHidden"] = t.IsHidden.Bool data["Cores"] = t.Cores.Int32 data["Ram"] = t.Ram.Float64 return json.Marshal(data) }
代码说明
- 实现
MarshalJSON方法后,调用json.Marshal(resObj)时会自动触发自定义序列化逻辑 - 对于
sql.NullString,当Valid为false时输出null,否则输出实际字符串 - 对于
sql.NullBool、sql.NullInt32、sql.NullFloat64,直接输出对应基础类型值(符合预期示例中的格式)
补充:反序列化支持(可选)
如果后续需要将JSON反序列化回TrnVmSeries结构体,需实现json.Unmarshaler接口:
func (t *TrnVmSeries) UnmarshalJSON(data []byte) error { type Alias TrnVmSeries aux := &struct { VmCode *string `json:"VmCode"` *Alias }{ Alias: (*Alias)(t), } if err := json.Unmarshal(data, aux); err != nil { return err } if aux.VmCode != nil { t.VmCode.String = *aux.VmCode t.VmCode.Valid = true } else { t.VmCode.Valid = false } t.IsHidden.Valid = true t.Cores.Valid = true t.Ram.Valid = true return nil }
验证效果
修改结构体后,原ReadSqlData函数无需改动,执行后会输出预期的扁平化JSON格式。
内容的提问来源于stack exchange,提问作者ARUNKUMAR RAVI
相关产品推荐
相关产品推荐

