我引用了irbanana关于支持PostGIS的空间数据类型的回答。我正在使用MySQL,并试图为自定义数据类型实现Value()
EWKBGeomPoint。
我的Gorm模型:
import (
"github.com/twpayne/go-geom"
"github.com/twpayne/go-geom/encoding/ewkb"
)
type EWKBGeomPoint geom.Point
type Tag struct {
Name string `json:"name"`
json:"siteID"` // forign key
Loc EWKBGeomPoint `json:"loc"`
}
据我所知,MySQL支持这样的插入:
INSERT INTO `tag` (`name`,`loc`) VALUES ('tag name',ST_GeomFromText('POINT(10.000000 20.000000)'))
或
INSERT INTO `tag` (`name`,`loc`) VALUES ('tag name', ST_GeomFromWKB(X'0101000000000000000000F03F000000000000F03F'))
如果我使用自己的Value()
来满足database/sql
的Valuer
界面:
func (g EWKBGeomPoint) Value() (driver.Value, error) {
log.Println("EWKBGeomPoint value called")
b := geom.Point(g)
bp := &b
floatArr := bp.Coords()
return fmt.Sprintf("ST_GeomFromText('POINT(%f %f)')", floatArr[0], floatArr[1]), nil
}
包括ST_GeomFromText()
在内的整个值在Gorm的单引号中引用,因此它不起作用:
INSERT INTO `tag` (`name`,`loc`) VALUES ('tag name','ST_GeomFromText('POINT(10.000000 20.000000)')');
我如何让它工作?
编辑1:
我追踪Gorm代码,最终得到了callback\u create.go
的createCallback
函数。在它内部检查,如果primaryField==nil
且为真,则它进入调用scope.SQLDB().Exec
,然后我无法进一步跟踪。
scope.SQL是字符串插入
标记
(
name,
loc)值(?,)
和scope.SQLVars
打印[标记名{{12[10 20]0}]
。看起来插值发生在这个调用中。
这是对
数据库/sql
代码的调用吗?
编辑2:
在这里找到了类似的Stackoverflow问题。但是我不明白解决办法。
更新:这种方法不起作用。
钩子可以让您在gorm的sql生成之前将列设置为gorm.Expr。
例如,插入之前的类似内容:
func (t *Tag) BeforeCreate(scope *gorm.Scope) error {
x, y := .... // tag.Loc coordinates
text := fmt.Sprintf("POINT(%f %f)", x, y)
expr := gorm.Expr("ST_GeomFromText(?)", text)
scope.SetColumn("loc", expr)
return nil
}
这是另一种方法;使用二进制编码。
根据该文档,MySQL使用4个字节存储几何值,以指示SRID(空间参考ID),然后是值的WKB(众所周知的二进制)表示。
因此,类型可以使用WKB编码,并在Value()和Scan()函数中添加和删除四字节前缀。在其他答案中找到的go geom库有一个WKB编码包,github.com/twpayne/go-geom/encoding/WKB。
例如:
type MyPoint struct {
Point wkb.Point
}
func (m *MyPoint) Value() (driver.Value, error) {
value, err := m.Point.Value()
if err != nil {
return nil, err
}
buf, ok := value.([]byte)
if !ok {
return nil, fmt.Errorf("did not convert value: expected []byte, but was %T", value)
}
mysqlEncoding := make([]byte, 4)
binary.LittleEndian.PutUint32(mysqlEncoding, 4326)
mysqlEncoding = append(mysqlEncoding, buf...)
return mysqlEncoding, err
}
func (m *MyPoint) Scan(src interface{}) error {
if src == nil {
return nil
}
mysqlEncoding, ok := src.([]byte)
if !ok {
return fmt.Errorf("did not scan: expected []byte but was %T", src)
}
var srid uint32 = binary.LittleEndian.Uint32(mysqlEncoding[0:4])
err := m.Point.Scan(mysqlEncoding[4:])
m.Point.SetSRID(int(srid))
return err
}
使用MyPoint类型定义标记:
type Tag struct {
Name string `gorm:"type:varchar(50);primary_key"`
Loc *MyPoint `gorm:"column:loc"`
}
func (t Tag) String() string {
return fmt.Sprintf("%s @ Point(%f, %f)", t.Name, t.Loc.Point.Coords().X(), t.Loc.Point.Coords().Y())
}
使用类型创建标记:
tag := &Tag{
Name: "London",
Loc: &MyPoint{
wkb.Point{
geom.NewPoint(geom.XY).MustSetCoords([]float64{0.1275, 51.50722}).SetSRID(4326),
},
},
}
err = db.Create(&tag).Error
if err != nil {
log.Fatalf("create: %v", err)
}
MySQL结果:
mysql> describe tag;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| name | varchar(50) | NO | PRI | NULL | |
| loc | geometry | YES | | NULL | |
+-------+-------------+------+-----+---------+-------+
mysql> select name, st_astext(loc) from tag;
+--------+------------------------+
| name | st_astext(loc) |
+--------+------------------------+
| London | POINT(0.1275 51.50722) |
+--------+------------------------+
我已经阅读了这里的文章和在使用JAXB时处理数字签名的示例代码,并且遇到了一个问题,我认为是JAXB封送将名称空间引入“signedinfo”元素。 我定义了一个XSD,它将被用不同编程语言实现的多个应用程序使用。我将XSD编译为JAXB注释类,供我的实现(Jersey JAX-RS和JAX-WS)使用。我目前拥有的流量如下: JAXB对象使用适当的数据创建或从远程应用程序传递。 按照Blaise
问题内容: 我有一段 一个如何在CSS中用空格表示id和class 当我使用 它不适用于以上的CSS。 问题答案: 实际上代表了两个不同的类 将不起作用,但您可能最终会获得实际的para编号
我有这样一个问题:我可以写到一个带有地理类型列的Postgis表,并且数据输入正确。当我试图取回它时,我得到了一个java.lang.IllegalArgumentException:不能转换org.PostgreSQL.util.PGObject类型的对象 我使用的是Hibernate Spatial 4.0M1、PostGIS2.0.2、Postgresql 9.1.7和Spring3.2、P
问题内容: 抱歉,很长的帖子! 我有一个包含约30个表的数据库(InnoDB引擎)。这些表中只有两个表,即“ transaction”和“ shift”非常大(第一个表有150万行,而shift有23000行)。现在一切正常,我对当前的数据库大小没有任何问题。 但是,我们将有一个类似的数据库(相同的数据类型,设计等),但数据库更大,例如,“事务”表将具有约 10亿条记录 (每天约有 230 万笔交
问题内容: 我想使用Gorm 来获取具有out_time的最后一个visit_details行。 本身就是VisitDetail OutTime为的类型。 码:- 查询: 问题答案: Go不能特别识别NULL。我认为您可以使用GORM中的原始查询来实现。像这样。 这是一个获取专栏的文章。希望这可以帮助。