英文:
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)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论