【问题标题】:Bind multiple columns in an array/struct with a single table将数组/结构中的多个列与单个表绑定
【发布时间】:2014-09-01 21:04:51
【问题描述】:

我想使用一个 orm。我查看了here 以找到一些带有文档的文档。我面临的问题是,这些 orms 似乎都无法将多个列绑定到数组或子结构中。

为了清楚起见,这里是一个例子。我有一张看起来像这样的桌子:

Table User
----------
UserId
UserName
UserPositionX
UserPositionY
UserPositionZ

理想情况下,我想将字段绑定到这个结构中(该数组要与我在客户端使用的另一个 API 保持一致):

type User struct {
    Id int64
    Name string
    Position [3]float64
}

其中UserPositionX 绑定到Position[0]UserPositionY 绑定到Position[1]UserPositionZ 绑定到Position[2]

我愿意使用这样的结构而不是数组:

type Vector3 struct {
    X, Y, Z float64
}

type User struct {
    Id int64
    Name string
    Position Vector3
}

但是我面临两个问题:

  • 我不想在另一个表中分隔Position 字段。我查看的所有 orms 似乎都认为 1 struct = 1 table。
  • 必须将此结构转换(编组)为 json。在这个 json 中,我需要位置是一个数组(例如:{"id": 42, name: "Foo", position: [6.3, 8.6, 2.65]})。

所以我的问题是:是否有适用于 go(和 sqlite)的 orm 能够在不创建另一个表的情况下绑定数组或结构中的多个列?如果无法使用数组,有没有办法自定义特定类型如何编组到 json 中?


编辑

我找到了一种方法来更改特定类型转换为 json 的方式。我只需要向给定类型添加两个方法。在这个例子中:

func (p *Vector3) MarshalJSON() ([]byte, error) {
    return []byte(fmt.Sprintf("[%v,%v,%v]", p.X, p.Y, p.Z)), nil
}

func (p *Vector3) UnmarshalJSON(data []byte) (err error) {
    _, err = fmt.Sscanf(string(data), "[%v,%v,%v]", &p.X, &p.Y, &p.Z)
    return
}

结果:

test, _ := json.Marshal(User{3, "fooBarBaz", Vector3{42.0, 35, 23.45}})
fmt.Println(string(test))
// ==> {"Id":3,"Name":"fooBarBaz","Position":[42.0,35,23.45]}

test2 := User{}
json.Unmarshal([]byte(`{"Id":3,"Name":"fooBarBaz","Position":[42.0,35,23.45]}`), &test2)
log.Println(test2)
// ==> {3 fooBarBaz {42.0 35 23.45}}

我最初的问题仍然存在,因为我测试了列表中的一些 orms,我发现的唯一方法是嵌入结构,我需要 Vector3 作为属性。

【问题讨论】:

  • 顺便说一句。完全可以回答您自己关于 SO 的问题,以防您不知道这一点。
  • @TheHippo 我知道,但我的编辑没有回答这个问题。

标签: json sqlite orm go


【解决方案1】:

在这种情况下,您需要结合database/sql 包和sql 数据库的功能:

  1. 您需要将带有GROUP_CONCAT 的职位列分组到一个逗号分隔的列表中。
  2. 您需要在您的类型上实现sql.Scanner 接口,以将逗号分隔的列表映射到数组。

第一步,您可以查看现有的questions

对于第二步,您可以使用以下内容:

type Foo struct {
    Bar []string
}

func (f *Foo) Scan(src interface{}) error {
    switch t := src.(type) {
    // t would then equal "value1, value2, value3"
    case string:
        *f = strings.Split(t, ",")

        return nil
    }

    return ErrBadScanType
}

Example 其中将key1:value1, key2:value2, ... 映射到一个对象。

PS:如果您的数据库支持,您还应该考虑使用一些特殊的geo 数据类型来存储向量。

【讨论】:

  • 感谢您的回答,但这种方式并没有真正优化。
  • @SebastienC。为什么没有优化?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-10
  • 2016-04-23
  • 2011-10-27
  • 1970-01-01
  • 2022-01-21
相关资源
最近更新 更多