Postgresql 使用Gorm插入和选择PostGIS几何图形
我一直在试图找到一种使用Golang,特别是库来插入和检索几何类型的方法。我还尝试使用定义不同几何图形类型的库,并提供不同格式之间的编码/解码 Orb已经为每种类型实现了Postgresql 使用Gorm插入和选择PostGIS几何图形,postgresql,go,postgis,go-gorm,wkb,Postgresql,Go,Postgis,Go Gorm,Wkb,我一直在试图找到一种使用Golang,特别是库来插入和检索几何类型的方法。我还尝试使用定义不同几何图形类型的库,并提供不同格式之间的编码/解码 Orb已经为每种类型实现了Scan()和Value()方法。这允许go的Insert()和Scan()函数处理基元以外的类型。然而,Orb希望使用以众所周知的二进制(WKB)格式表示的几何体 orb文档显示,要实现这一点,只需将字段包装在PostGIS函数ST_AsBinary()和ST_GeomFromWKB()中,分别用于查询和插入。例如,表定义为:
Scan()
和Value()
方法。这允许go的Insert()
和Scan()
函数处理基元以外的类型。然而,Orb希望使用以众所周知的二进制(WKB)格式表示的几何体
orb文档显示,要实现这一点,只需将字段包装在PostGIS函数ST_AsBinary()
和ST_GeomFromWKB()
中,分别用于查询和插入。例如,表定义为:
_, err = db.Exec(`
CREATE TABLE IF NOT EXISTS orbtest (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
geom geometry(POLYGON, 4326) NOT NULL
);
`)
您只需执行以下操作:
rows, err := db.Query("SELECT id, name, ST_AsBinary(geom) FROM orbtest LIMIT 1")
对于插入(其中p为圆点):
这是我的问题:通过使用GORM,我没有能力用这些函数构建这些查询。GORM将自动向给定结构的数据库中插入值,并将数据扫描到结构的整个层次结构中。那些Scan()
和Value()
方法是在幕后调用的,不受我的控制
试图直接将二进制数据插入到几何列中是行不通的,而直接查询几何列将以十六进制给出结果
我尝试了多种数据库方法来解决这个问题。我尝试创建自动调用几何体列上所需函数的视图。这适用于查询,但不适用于插入
是否有可能制定某种触发器或规则,对输入/输出的数据自动调用所需的函数
我还应该注意到,我正在使用的库完全独立于数据和模式,因此我没有硬编码任何类型查询的特权。我当然可以编写一个函数来扫描整个数据模型,并从头开始生成查询,但我更希望有更好的选择
有人知道用SQL实现这一点的方法吗?仅仅通过查询列本身就能够自动调用列上的函数吗
如有任何建议,将不胜感激
是否有可能制定某种触发器或规则,对输入/输出的数据自动调用所需的函数
曾经尝试过gorm挂钩,例如:
类型示例结构{
ID int
名称字符串
几何。。。
}
func(e*示例)AfterFind()(错误){
e、 Geom=…//在这里做你喜欢做的事
返回
}
你可以使用一些。我发现它们非常简洁实用。我最终使用的解决方案如下: 首先,我创建了包装所有orb类型的新类型,例如:
type Polygon4326 orb.Polygon
type Point4326 orb.Point
然后我在每种类型上实现了Scan()
,Value()
方法。然而,我不得不编辑字节并将其转换为十六进制。在PostGIS中直接查询空间列时,它将返回EWKB的十六进制表示形式,基本上是WKB,但包含4个字节来表示投影ID(在我的示例中是4326)
在插入之前,我必须添加表示4326投影的字节
在阅读之前,我必须去除这些字节,因为orb内置的扫描需要WKB格式。我使用@robbieperry22的答案和不同的编码库,发现我根本不需要修补字节 包括参考要点
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()
我最终使用的另一个解决方案是with,因为我发现我需要使用GEOS C库。这样,我就可以将结构转换为
WKT
进行插入(因为postgis接受它作为常规文本),并在扫描时从WKB
进行转换
类型Geometry4326*geos.Geometry
//值将给定的Geometry4326结构转换为WKT,以便将其存储在
//数据库。实现用于数据库操作的Valuer接口。
func(g Geometry4326)Value()(driver.Value,错误){
str,err:=g.ToWKT()
如果错误!=零{
返回零,错误
}
返回“SRID=4326;”+str,无
}
//扫描将几何图形的十六进制表示形式转换为给定的几何图形4326
//结构。实现用于数据库操作的扫描仪接口。
func(g*Geometry4326)扫描(值接口{})错误{
字节,确定:=值。([]字节)
如果!好的{
返回错误。新建(“无法将数据库值转换为几何图形”)
}
str:=字符串(字节)
geom,err:=geos.FromHex(str)
如果错误!=零{
返回错误。换行(错误,“无法从十六进制获取几何体”)
}
几何图形:=几何图形4326(几何图形)
*g=几何体
归零
}
此解决方案可能并不适合所有人,因为并非所有人都需要使用GEOS C库,这可能会让人难以在windows上工作。但我确信,同样的事情可以通过使用不同的库来完成
另外,我在struct上实现了UnmarshalJSON()
和MarshalJSON()
,这样它就可以自动封送/取消封送GeoJSON,然后无缝地从数据库保存/获取。我使用将GeoJSON转换为结构体/从结构体转换为结构体,然后将所述结构体转换为我正在使用的结构体。有点复杂,是的,但它是有效的
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()