在golang xorm中使用postgresql的json,array类型的操作

时间:2022-10-19 12:13:19

xorm支持各种关系数据库,最近使用postgresql时,总是踩到一些坑,在此记录下解决方式。

在使用postgresql的array类型时,查询有点问题,xorm的官方文档给出重写的方式,但是不是很清晰:

官方文档链接:http://xorm.io/docs

在golang xorm中使用postgresql的json,array类型的操作

也就是说碰到基础库不支持的类型,需要我们去重写ToDB、FromDB方法,废话不多说直接上代码:

比如int8[]类型,自定一个Int64Array

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
type Int64Array []int64
 
func (s *Int64Array) FromDB(bts []byte) error {
    if len(bts) == 0 {
        return nil
    }
 
    str := string(bts)
    if strings.HasPrefix(str, "{") {
        str = "[" + str[1:len(str)]
    }
 
    if strings.HasSuffix(str, "}") {
        str = str[0: len(str)-1] + "]"
    }
 
    var ia = &[]int64{}
 
    err := json.Unmarshal([]byte(str), ia)
    if err != nil {
        return err
    }
 
    *s = Int64Array(*ia)
    return nil
}
 
func (s *Int64Array) ToDB() ([]byte, error) {
    return serializeBigIntArray(*s, "{", "}"), nil
}
 
func (arr Int64Array) MarshalJSON() ([]byte, error) {
    return serializeBigIntArrayAsString(arr, "[", "]"), nil
}
 
func (arr *Int64Array) UnmarshalJSON(b []byte) error {
    var strarr []string
    var intarr []int64
 
    err := json.Unmarshal(b, &strarr)
    if err != nil {
        return err
    }
 
    for _, s := range strarr {
        i, err := strconv.ParseInt(s, 10, 64)
        if err != nil {
            return err
        }
 
        intarr = append(intarr, i)
    }
 
    *arr = intarr
    return nil
}
 
func serializeBigIntArray(s []int64, prefix string, suffix string) []byte {
    var buffer bytes.Buffer
 
    buffer.WriteString(prefix)
 
    for idx, val := range s {
        if idx > 0 {
            buffer.WriteString(",")
        }
        buffer.WriteString(strconv.FormatInt(val, 10))
    }
 
    buffer.WriteString(suffix)
 
    return buffer.Bytes()
}
 
func serializeBigIntArrayAsString(s []int64, prefix string, suffix string) []byte {
    var buffer bytes.Buffer
 
    buffer.WriteString(prefix)
 
    for idx, val := range s {
        if idx > 0 {
            buffer.WriteString(",")
        }
        buffer.WriteString("\"")
        buffer.WriteString(strconv.FormatInt(val, 10))
        buffer.WriteString("\"")
    }
    buffer.WriteString(suffix)
    return buffer.Bytes()
}

json类型:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
type Cover struct {
 Id   int64  `json:"id,omitempty"`
 Fid  string `json:"fid,omitempty"`
 Type int8   `json:"type,omitempty"`
 Url  string `json:"url,omitempty"`
}
 
func (c *Cover) FromDB(bytes []byte) error {
 return json.Unmarshal(bytes, c)
}
 
func (c *Cover) ToDB() (bytes []byte, err error) {
 bytes, err = json.Marshal(c)
 return
}

具体使用:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
type Course struct {
    Id            int64             `json:"id,string" form:"id"`
    Name          string            `json:"name" form:"name"`
    Brief         string            `json:"brief" form:"brief"`
    Description   string            `json:"description" form:"description"`
    Cover         common.Cover      `xorm:"Text" json:"cover" form:"cover"`
    Categories    common.Int64Array `xorm:"Text" json:"categories" form:"categories[]"`
    Tags          common.Int64Array `json:"tags" form:"tags[]"`
    Difficulty    float64           `json:"difficulty" form:"difficulty"`
    Price         float64           `json:"price" form:"price"`
    Markets       common.Int64Array `json:"markets" form:"markets[]"`
    StudentAmount int64             `json:"studentAmount" form:"studentAmount"`
    SubjectAmount int64             `json:"subjectAmount" form:"subjectAmount"`
    Crt           time.Time         `json:"crt"`
    Lut           time.Time         `json:"lut"`
    Status        int16             `json:"status" form:"status"`
    common.Page                     `xorm:"-"`
}

补充:golang gin xorm注意事项

1. 无论是golang还是xorm中,在填写j'son字段时,注意空格,比如 `json:"abcd "` `json:"abcd"`是不一样的,不仔细对比会出错

2.当结合gin框中的

?
1
c.JSON(http.StatusOK,gin.H{})操作

并且使用xorm中的join,find操作时(https://www.kancloud.cn/xormplus/xorm/167102)要注意如下现象,

假如定义两个结构体对应两个表

在golang xorm中使用postgresql的json,array类型的操作

然后使用联合查询,先把两个结构体结合成一个结构体,假如如下,在UserGroup中使用User和Group匿名结构体,

在golang xorm中使用postgresql的json,array类型的操作

那么当我们使用gin的c.JSON(http.StatusOK,gin.H{"data":UserGroup})返回数据时会导致Group和User中同名字段显示不了,这应该是gin和xorm的不是很兼容造成的(没有深究),

要解决这个问题,最好让UserGroup中的User和Group不要以匿名结构体的形式存在

可以改成

?
1
2
3
4
type UserGroup struct {
    MyUser  User `xorm:"extends" json:"你要json中返回的名字"`
    MyGroup Group `xorm:"extends" json:"你要json中返回的名字"`
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。如有错误或未考虑完全的地方,望不吝赐教。

原文链接:https://blog.csdn.net/WwJoyous/article/details/80430613