我一直在试图找到一种使用Golang插入和检索几何类型的方法,特别是库gorm.我还试图使用库orb,它为几何定义了不同的类型,并提供不同格式之间的编码/解码.

ORB已经为每种类型实现了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是一个圆点):

db.Exec("INSERT INTO orbtest (id, name, geom) VALUES ($1, $2, ST_GeomFromWKB($3))", 1, "Test", wkb.Value(p))

我的问题是:通过使用GORM,我无法使用这些函数构建这些查询.在给定 struct 的情况下,GORM将自动将值插入到数据库中,并将数据扫描到 struct 的整个层次 struct 中.这Scan()Value()方法是在幕后调用的,不受我的控制.

试图直接将二进制数据插入几何列是行不通的,而直接查询几何列将以十六进制给出结果.

我try 了多种数据库方法来解决这个问题.我try 创建自动调用几何列上所需函数的视图.这适用于查询,但不适用于插入.

是否可以创建某种类型的触发器或规则,自动调用传入/传出数据所需的函数?

我还应该注意到,我正在使用的库完全独立于数据和模式,因此我没有硬编码任何类型查询的特权.我当然可以编写一个函数来扫描整个数据模型,并从头开始生成查询,但我更希望有更好的 Select .

有人知道用SQL实现这一点的方法吗?只需查询列本身,就能自动调用列上的函数吗?

如有任何建议,将不胜感激.

推荐答案

我最终使用的另一个解决方案是go-geos,因为我发现我需要使用GEOS C库.这样,我就可以将 struct 转换为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上工作可能会很痛苦.但我相信,同样的事情可以通过使用不同的库来完成.

我在struct上另外实现了UnmarshalJSON()MarshalJSON(),这样它就可以自动封送/解封GeoJSON,然后无缝地从数据库中保存/获取.我使用geojson-go将GeoJSON转换为 struct ,然后使用geojson-geos-go将所述 struct 转换为我正在使用的go-geos struct .有点复杂,是的,但它是有效的.

Go相关问答推荐

Golang regexpp:获取带有右括号的单词

无法在Macos上使用Azure Speech golang SDK

如何在jsonrpc服务器的服务器端捕获错误?

使用GO从RDPMC获得价值

如果values.yaml文件中不存在某个属性,如何返回默认的FALSE?

如何在链接中写入链接

Golang Gorm Fiber / argon2.Config 未定义

优化方式中所有可能组合的字符串相似度

Go time.Parse 无效的 ISO 日期

如何忽略打印达到最大深度限制 go colly

Go 中的 Azure JWT 验证不起作用

我的神经网络(从头开始)训练,让它离目标更远

使用 Go 根据 /etc/shadow 文件中的散列密码验证密码

为什么不同的 Wireguard 私钥会产生相同的公钥?

Go Colly 如何找到请求的元素?

Go 信号处理程序不处理终端窗口关闭

转换朴素递归硬币问题时的记忆错误

Go 并发、goroutine 同步和关闭通道

gorm 获取列名

如何在 Windows 中使用 github.com/AllenDang/giu 和 github.com/gordonklaus/portaudio 构建 GO 程序