如何使用GORM存储嵌入式结构体?

huangapple go评论78阅读模式
英文:

How to store embedded struct with GORM?

问题

你好!要将嵌入式结构体存储到GORM中,你可以使用GORM的标签来指定字段的映射方式。在你的例子中,你可以在A结构体中使用gorm:"embedded"标签来告诉GORM将point字段作为嵌入式结构体处理,而不是创建一个新的表。

下面是修改后的代码示例:

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

type GeoPoint struct {
    Lat float64
    Lon float64
}

这样,GORM将会将point字段作为A表的一个字段进行存储,而不是创建一个新的表。

希望对你有帮助!如果你还有其他问题,请随时提问。

英文:

How can I store an embedded struct with GORM if I have a type like this

type A struct {
    point GeoPoint
}

type GeoPoint struct {
    Lat float64
    Lon float64
}

GORM tries to add it in a new table, but I want to add it as another field.

How can this be done?

答案1

得分: 6

对于任何想要在GORM模型中放置结构体并自动进行编组和解组的人来说,这是一个解决方案。这个解决方案基于chris的答案,并且它是有效的。

例如,我想在Parent中将Children的数组作为编组的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"`
}

希望对你有帮助!

英文:

For anyone, who's searching the way to put struct inside GORM model and make it marshalling and unmarshalling automatically.

This solution is based on chris's answer. And it works!

For example, I want to put array of Childrens inside Parent as marshalled 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"`
}

答案2

得分: 5

你可以尝试:

   类型 A struct {
    point GeoPoint `gorm:"embedded"`
}
英文:

You can try:

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

答案3

得分: 0

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

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("(%f,%f)", 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)
}

请注意,我只翻译了代码部分,其他内容不做翻译。

英文:

I am not familiar with Gorm, but with sqlx you will need to implement the sql.Scanner and sql.Valuer interfaces to allow the data to be converted to the postgres point type. The code below isn't checking for errors so it will need some tweaks.

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

得分: -1

首先,使用gorm时,你不应该将字段的首字母小写。

如果你确保GeoPoint与A表关联,你可以使用ForeignKey标签,例如:
确保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)
}
英文:

First, using gorm you never define fields with the first letter in lower case.

If you make sure GeoPoint is linked as Aid , you can use ForeingKey tag like,
MAKE SURE Id is table A 's primary key.

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)
}

If not linked by primary key. You can use middleware like

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)
}

huangapple
  • 本文由 发表于 2015年2月13日 23:29:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/28503001.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定