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

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

是否需要同時實現 Scanner 接口和 Valuer 接口

是否需要同時實現 Scanner 接口和 Valuer 接口

Go
一只萌萌小番薯 2023-07-26 19:58:06
我正在處理一個要求,其中我收到一個 JSON 對象,其中包含一個字符串形式的日期值。我的任務是將 Date 對象存儲在數據庫中。類似這樣的事情:{"start_date": "2019-05-29", "end_date": "2019-08-30"}{"start_date": "2019-05-29", "end_date": null}我已經實現了自定義Date類型type Date struct {? ? time.Time}我已經實現了 UnmarshalJSON 接口func (d *Date) UnmarshalJSON(b []byte) (err error) {? ? if b[0] == '"' && b[len(b)-1] == '"' {? ? ? ? b = b[1 : len(b)-1]? ? }? ? // take care of null..? ? if len(b) == 0 || string(b) == "null" {? ? ? ? d.Time = time.Time{}? ? ? ? return? ? }? ? d.Time, err = time.Parse("2006-01-02", string(b))? ? return}還實現了 Valuer 接口以將 Value 返回給 sql.Driver。func (d Date) Value() (driver.Value, error) {? ? // check if the date was not set..? ? if d.Time.IsZero() {? ? ? ? return nil, nil? ? }? ? return d.Time.Format("2006-01-02"), nil}但由于某種原因,直到Date 實現 Scanner 接口,就像這樣:func (d Date) Scan(b interface{}) (err error) {? ? ...? ? return}問題:ORM 適配器 (GORM) 不會將記錄存儲在數據庫中。有什么線索嗎?如果我運行上面的代碼 2 兩次,我會看到不同的行為,具體取決于 Scan() 函數是否存在。
查看完整描述

2 回答

?
素胚勾勒不出你

TA貢獻1827條經驗 獲得超9個贊

上一篇:我跑了go get -u github.com/jinzhu/gorm。我將使用sqlite而不是pgsql. 供參考,go version go1.12.7 linux/amd64

  1. 您的注釋未使用正確的語法。gorm-屬性-值對的分隔符不是comma,而是semi-colon。https://github.com/jinzhu/gorm/blob/master/model_struct.go#L644

  2. 的實現Date.Scan()必須使用指針接收器,否則您會丟失更新的值。https://github.com/jinzhu/gorm/blob/0fd395ab37aefd2d50854f0556a4311dccc6f45a/scaner_test.go#L57

  3. 在我的測試期間,Scan方法收到一個time.Time,因此不需要nil大小寫,也不string需要大小寫(可能是數據庫驅動程序的問題)。然而,更重要的是,我添加了一個default案例來捕獲不受支持的類型。

  4. Scan方法涉及將從數據庫讀取的數據分配給您提供的對象的過程。評論它與您在上次 sql 結果復制粘貼中演示的缺失日期問題無關。我認為這在某種程度上與我之前提到的問題有關。

  5. 我聽取了所有錯誤以確保一切按預期工作。

這是我的測試代碼,

package main


import (

    "database/sql/driver"

    "encoding/json"

    "fmt"

    "log"

    "time"


    "github.com/jinzhu/gorm"

    _ "github.com/jinzhu/gorm/dialects/sqlite"

)


var DB *gorm.DB


type CustomerBroker struct {

    gorm.Model

    StartDate Date `gorm:"type:date;column:start_date" json:"start_date"`

    EndDate   Date `gorm:"type:date;column:end_date" json:"end_date"`

}


type Date struct {

    time.Time

}


func (d *Date) UnmarshalJSON(b []byte) (err error) {

    if b[0] == '"' && b[len(b)-1] == '"' {

        b = b[1 : len(b)-1]

    }


    // take care of null..

    if len(b) == 0 || string(b) == "null" {

        d.Time = time.Time{}

        return

    }


    d.Time, err = time.Parse("2006-01-02", string(b))

    return

}


func (d *Date) Scan(b interface{}) (err error) {

    switch x := b.(type) {

    case time.Time:

        d.Time = x

  default:

    err = fmt.Errorf("unsupported scan type %T", b)

    }

    return

}


func (d Date) Value() (driver.Value, error) {

    // check if the date was not set..

    if d.Time.IsZero() {

        return nil, nil

    }

    return d.Time.Format("2006-01-02"), nil

}


func main() {

    var dberr error

    DB, dberr = gorm.Open("sqlite3", ":memory:")

    if dberr != nil {

        panic(dberr)

    }

    defer DB.Close()

    record := CustomerBroker{}

    errs := DB.CreateTable(record).GetErrors()

    fmt.Println("create error ", errs)

    data := []byte(`{"start_date": "2019-05-29", "end_date": null}`)

    err := json.Unmarshal(data, &record)

    fmt.Println("unmarshal error ", err)

    log.Printf("record start %v end %v\n", record.StartDate, record.EndDate)

    errs = DB.Create(&record).GetErrors()

    fmt.Println("insert error ", errs)

    all := []CustomerBroker{}

    errs = DB.Find(&all).GetErrors()

    fmt.Println("find error ", errs)

    log.Printf("records count %v\n", len(all))

    for _, a := range all {

        log.Printf("found start %v end %v\n", a.StartDate, a.EndDate)

    }

}

輸出:


$ go run main.go 

create error  []

unmarshal error  <nil>

2019/10/11 17:22:51 record start 2019-05-29 00:00:00 +0000 UTC end 0001-01-01 00:00:00 +0000 UTC

insert error  []

find error  []

2019/10/11 17:22:51 records count 1

2019/10/11 17:22:51 found start 2019-05-29 00:00:00 +0000 UTC end 0001-01-01 00:00:00 +0000 UTC

如果您在運行此命令時發現不同的行為pqsql,請共享相應的 docker 映像,以便將來可以針對同一版本進行嘗試。


查看完整回答
反對 回復 2023-07-26
?
慕容708150

TA貢獻1831條經驗 獲得超4個贊

啟用DB.LogMode(true)顯示這兩個查詢

與掃描:

[2019-10-16?14:03:34]??[0.97ms]??INSERT??INTO?"custom_brokers"?("created_at","updated_at","deleted_at","start_date","end_date")?VALUES?('2019-10-16?14:03:34','2019-10-16?14:03:34',NULL,'2019-05-29',NULL)?RETURNING?"custom_brokers"."id"

無需掃描:

[2019-10-16?14:02:53]??[0.76ms]??INSERT??INTO?"custom_brokers"?("created_at","updated_at","deleted_at")?VALUES?('2019-10-16?14:02:53','2019-10-16?14:02:53',NULL)?RETURNING?"custom_brokers"."id"

第二個顯示 gorm 完全忽略模型中的另一列(嵌入式 gorm 模型除外)

查看完整回答
反對 回復 2023-07-26
  • 2 回答
  • 0 關注
  • 162 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

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

幫助反饋 APP下載

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

公眾號

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