最小代码结构

image.png
使用
image.png

自定义MarshalJSON只加在外层不会有这个问题,只要里面添加,目前发现不管外面的自定义MarshalJSON写不写,怎么写,都存在数据丢失的情况

问题原理

待进一步研究,简单看了下源码,跑了下,两个自定义MarshalJSON都会被执行,先内再外,目前没有深入研究

解决方法

线上发生情况是查询数据,最终返回树状结构数据,需要增加几个字段以及Children,为了便于理解和维护,没有改变原表结构体,直接用了,也就是上面最小代码结构的形式的复杂版,所以方向有几个:

  1. 不要使用组合,在原表上添加不映射列的字段,并写好备注,类似如下
    image.png
    缺点:直接拿这张表的数据的时候,会有很多默认的空值,容易造成歧义
  2. 把内部的MarshalJSON删掉
    缺点:实际表使用的时候的需要自定义MarshalJSON的内容无法正常使用
  3. 不要用组合,而是给一个新字段,把两部分数据分开
    image.png
    缺点:用的时候稍微麻烦一点点,需要从里面取值
  4. 表和数据的返回结构完全分开,写两份
    缺点:改表的字段后需要同步修改所有使用这个表的返回数据的字段
  5. 期待其他解决方法,目前暂时没发现,发现后更新

下面代码是用来断点调试看源码的测试代码

package main

import (
    "encoding/json"
    "log"
)

type Inter struct {
    Title string `json:"title"`
}

func (r *Inter) MarshalJSON() ([]byte, error) {
    type Alias Inter
    return json.Marshal(&struct {
        Title string `json:"title"`
        Alias
    }{
        Title: r.Title,
        Alias: (Alias)(*r),
    })
}

type Test struct {
    Inter
    Name     string `json:"name"`
    Children *Test
}

type Test1 struct {
    Inter    Inter
    Name     string `json:"name"`
    Children *Test
}

func (r *Test) MarshalJSON() ([]byte, error) {
    type Alias Test
    log.Println("----", r.Children)
    return json.Marshal(&struct {
        Children *Test
        Name     string
        Alias
    }{
        Alias:    (Alias)(*r),
        Children: r.Children,
        Name:     r.Name,
    })
}
func main() {

    var tt []Test = make([]Test, 0)

    tt = append(tt, Test{
        Inter:    Inter{Title: "title1"},
        Name:     "level1",
        Children: nil,
    })
    tt = append(tt, Test{
        Name: "level2",
        Children: &Test{
            Name: "2222",
        },
    })

    ttStr, err := json.Marshal(tt)
    if err != nil {
        log.Println("--------err:---------")
        log.Println(err)
        return
    }
    log.Println(string(ttStr)) //  [{"title":"title1"},{"title":""}]
    log.Println("----------")
}

vincent
49 声望2 粉丝