【问题标题】:How to store embedded struct with GORM?如何使用 GORM 存储嵌入式结构?
【发布时间】:2015-04-14 16:41:53
【问题描述】:

如果我有这样的类型,如何使用 GORM 存储嵌入式结构

type A struct {
    point GeoPoint
}

type GeoPoint struct {
    Lat float64
    Lon float64
}

GORM 尝试将其添加到新表中,但我想将其添加为另一个字段。

如何做到这一点?

【问题讨论】:

  • 导出point 字段,将其设为大写。

标签: postgresql go


【解决方案1】:

对于任何正在寻找将 struct 放入 GORM 模型并使其自动编组和解组的方法的人。

此解决方案基于 chris 的回答。它有效!

例如,我想将 Childs 数组放入 Parent 作为编组 JSON:

type Child struct {
    Lat float64
    Lng float64
}

type ChildArray []Children

func (sla *ChildArray) Scan(src interface{}) error {
    return json.Unmarshal(src.([]byte), &sla)
}

func (sla ChildArray) Value() (driver.Value, error) {
    val, err := json.Marshal(sla)
    return string(val), err
}

type Parent struct {
    *gorm.Model    
    Childrens ChildArray `gorm:"column:childrens;type:longtext"`
}

【讨论】:

  • 对于Scan,我必须使用return json.Unmarshal([]byte(src.(string)), &sla),否则它会起作用!天才
【解决方案2】:

你可以试试:

   type A struct {
    point GeoPoint `gorm:"embedded"`
} 

【讨论】:

    【解决方案3】:

    我不熟悉 Gorm,但是使用 sqlx 需要实现 sql.Scanner 和 sql.Valuer 接口,以允许将数据转换为 postgres point 类型。下面的代码没有检查错误,因此需要进行一些调整。

    https://play.golang.org/p/2-Y-wSeAWnj

    package main
    
    import (
        "database/sql/driver"
        "fmt"
        "strconv"
        "strings"
    )
    
    type GeoPoint struct {
        Lat float64
        Lon float64
    }
    
    func (gp GeoPoint) Value() (driver.Value, error) {
        return fmt.Sprintf("(%d,%d)", gp.Lat, gp.Lon), nil
    }
    
    func (gp GeoPoint) Scan(src interface{}) error {
        raw := src.(string)
        coords := raw[1 : len(raw)-1]
        vals := strings.Split(coords, ",")
        gp.Lat, _ = strconv.ParseFloat(vals[0], 64)
        gp.Lon, _ = strconv.ParseFloat(vals[1], 64)
        return nil
    }
    
    func main() {
        gp := GeoPoint{Lat: 112, Lon: 53}
        d, _ := gp.Value()
        fmt.Printf("%+v\n", d)
    
        gp.Scan("(53, -110)")
        fmt.Printf("%+v\n", gp)
    }
    

    【讨论】:

      【解决方案4】:

      首先,使用 gorm,您永远不会使用小写的第一个字母来定义字段。

      如果您确保 GeoPoint 链接为 Aid ,您可以使用 ForeingKey 标签,例如, 确保 Id 是表 A 的主键。

      type A struct {
          Id int `gorm:"column:"id""`
          Point GeoPoint `gorm:"column:geo_point;ForeignKey:OrderId"`
      }
      
      type GeoPoint struct {
          Aid int
          Lat float64
          Lon float64
      }
      
      func main(){
          ...
          ...
          var as []A
          if e:=db.Model(&A{}).Find(&as).Error;e!=nil{
              handle(e)
          }
          fmt.Println(as)
      }
      

      如果没有通过主键链接。您可以使用中间件,如

      type A struct {
          Id int `gorm:"column:"id""`
          Point GeoPoint `gorm:"column:geo_point"`
      }
      
      func (a *A) AfterFind()error{
         return db.Model(&GeoPoint{}).First(&(a.Point)).Error
      }
      
      type GeoPoint struct {
          Aid int
          Lat float64
          Lon float64
      }
      
      func main(){
          ...
          ...
          var as []A
          if e:=db.Model(&A{}).Find(&as).Error;e!=nil{
              handle(e)
          }
          fmt.Println(as)
      }
      

      【讨论】:

        猜你喜欢
        • 2021-11-02
        • 1970-01-01
        • 1970-01-01
        • 2014-01-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-04-26
        相关资源
        最近更新 更多