4 回答
TA贡献1798条经验 获得超7个赞
包括要点以供参考。
import "github.com/twpayne/go-geom/encoding/geojson"
type EWKBGeomPoint geom.Point
func (g *EWKBGeomPoint) Scan(input interface{}) error {
gt, err := ewkb.Unmarshal(input.([]byte))
if err != nil {
return err
}
g = gt.(*EWKBGeomPoint)
return nil
}
func (g EWKBGeomPoint) Value() (driver.Value, error) {
b := geom.Point(g)
bp := &b
ewkbPt := ewkb.Point{Point: bp.SetSRID(4326)}
return ewkbPt.Value()
}
type Track struct {
gorm.Model
GeometryPoint EWKBGeomPoint `gorm:"column:geom"`
}
然后在表设置/迁移部分使用了一些定制:
err = db.Exec(`CREATE TABLE IF NOT EXISTS tracks (
id SERIAL PRIMARY KEY,
geom geometry(POINT, 4326) NOT NULL
);`).Error
if err != nil {
return err
}
err = gormigrate.New(db, gormigrate.DefaultOptions, []*gormigrate.Migration{
{
ID: "init",
Migrate: func(tx *gorm.DB) error {
return tx.CreateTable(
Tables...,
).Error
},
},
{
ID: "tracks_except_geom",
Migrate: func(tx *gorm.DB) error {
return db.AutoMigrate(Track{}).Error
},
},
}).Migrate()
TA贡献1818条经验 获得超11个赞
我最终使用的解决方案如下:
首先,我创建了包含所有 orb 类型的新类型,例如:
type Polygon4326 orb.Polygon type Point4326 orb.Point
然后我在每种类型上实现了Scan()
,方法。Value()
然而,我不得不编辑字节并转换为十六进制或从十六进制转换。当您直接查询 PostGIS 中的空间列时,它将返回 EWKB 的十六进制表示形式,本质上是 WKB,但包括 4 个字节来表示投影 ID(在我的例子中是 4326)。
在插入之前,我必须添加代表 4326 投影的字节。
在阅读之前,我不得不剥离那些字节,因为 orb 内置扫描预期的 WKB 格式。
TA贡献1820条经验 获得超10个赞
是否可以制作某种触发器或规则来自动调用传入/传出数据所需的函数?
曾经尝试过 gorm 钩子,例如:
type Example struct {
ID int
Name string
Geom ...
}
func (e *Example) AfterFind() (err error) {
e.Geom = ... // Do whatever you like here
return
}
您可以使用一些挂钩。我发现它们非常整洁且有用。
TA贡献1963条经验 获得超6个赞
我最终使用的另一个解决方案是使用go-geos,因为我发现我需要使用 GEOS C 库。这样,我就可以将结构转换为WKT
用于插入(因为 postgis 接受它作为常规文本)并WKB
在扫描时从中转换。
type Geometry4326 *geos.Geometry
// Value converts the given Geometry4326 struct into WKT such that it can be stored in a
// database. Implements Valuer interface for use with database operations.
func (g Geometry4326) Value() (driver.Value, error) {
str, err := g.ToWKT()
if err != nil {
return nil, err
}
return "SRID=4326;" + str, nil
}
// Scan converts the hexadecimal representation of geometry into the given Geometry4326
// struct. Implements Scanner interface for use with database operations.
func (g *Geometry4326) Scan(value interface{}) error {
bytes, ok := value.([]byte)
if !ok {
return errors.New("cannot convert database value to geometry")
}
str := string(bytes)
geom, err := geos.FromHex(str)
if err != nil {
return errors.Wrap(err, "cannot get geometry from hex")
}
geometry := Geometry4326(geom)
*g = geometry
return nil
}
此解决方案可能并不适合所有人,因为并非所有人都需要使用 GEOS C 库,这在 Windows 上工作可能会很痛苦。我确信同样的事情可以使用不同的库来完成。
我另外在结构上实现了UnmarshalJSON()
and ,以便它可以自动编组/解组 GeoJSON,然后无缝地保存/从数据库中获取。我使用geojson-go将 GeoJSON 转换为结构或从结构转换,然后使用geojson-geos-go将所述结构转换为我正在使用的go-geosMarshalJSON()
结构来完成此操作。有点复杂,是的,但它有效。
- 4 回答
- 0 关注
- 302 浏览
添加回答
举报