亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

使用 Gorm 和 MySQL 處理空間數據

使用 Gorm 和 MySQL 處理空間數據

Go
炎炎設計 2022-05-18 16:40:39
我參考了 irbanana關于支持 PostGIS 的空間數據類型的回答。我正在使用 MySQL 并嘗試實現Value()自定義數據類型EWKBGeomPoint。我的戈姆模型:import (    "github.com/twpayne/go-geom"    "github.com/twpayne/go-geom/encoding/ewkb")type EWKBGeomPoint geom.Pointtype 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's 的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 代碼,最終它得到了 tocallback_create.go的createCallback功能。在里面檢查if primaryField == nil它是真的,它進入調用scope.SQLDB().Exec然后我沒有進一步追蹤。scope.SQL 是字符串INSERT INTO標記(名稱,loc) VALUES (?,?)并scope.SQLVars打印[tag name {{1 2 [10 20] 0}}]. 看起來插值發生在這個調用中。這是調用database/sql代碼嗎?
查看完整描述

2 回答

?
叮當貓咪

TA貢獻1776條經驗 獲得超12個贊

這是另一種方法;使用二進制編碼。


根據此文檔,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) |

+--------+------------------------+

(ArcGIS 說4326 是用于在全世界存儲參考數據的最常見的空間參考。它是 PostGIS 空間數據庫和 GeoJSON 標準的默認值。它也被默認用于大多數 Web 制圖庫。)


查看完整回答
反對 回復 2022-05-18
?
慕桂英3389331

TA貢獻2036條經驗 獲得超8個贊

Hooks可以讓你在 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

}


查看完整回答
反對 回復 2022-05-18
  • 2 回答
  • 0 關注
  • 181 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號