golang – Save enum type to SQL database "panic: sql: converting Exec argument #1's type: non-Value type int returned from Value"

huangapple go评论95阅读模式
英文:

golang - Save enum type to SQL database "panic: sql: converting Exec argument #1's type: non-Value type int returned from Value"

问题

在你的代码中,出现了一个运行时错误"sql: converting Exec argument #1's type: non-Value type int returned from Value"。这个错误是由于在保存到数据库时,无法正确转换枚举类型的值所导致的。

为了解决这个问题,你需要在PlatformType类型的Value方法中返回一个driver.Value类型的值,而不是int类型的值。修改PlatformTypeValue方法如下:

func (u PlatformType) Value() (driver.Value, error) {
    return int64(u), nil
}

另外,你还需要在PlatformTypeScan方法中将值转换为PlatformType类型。修改PlatformTypeScan方法如下:

func (u *PlatformType) Scan(value interface{}) error {
    *u = PlatformType(value.(int64))
    return nil
}

通过这些修改,你应该能够正确保存枚举类型的值到数据库中。

至于你更大的问题,即如何将自定义的GO枚举类型保存到SQL数据库中(最好使用ORM引擎),你已经在代码中使用了gorm作为ORM引擎,这是一个很好的选择。你只需要按照上述修改的方式,为你的自定义枚举类型实现ValueScan方法,gorm会自动将其与数据库进行映射。

希望这能帮助到你!如果你还有其他问题,请随时提问。

英文:

In my current go project (~5K LOC), I am using sqlite3 as my underlying database layer, and I am using gorm as my ORM engine. One of the models is a Platform with a field of PlatformType enum type. Here's a code snippet to demonstrate my problem.

package main

import (
    _ "github.com/jinzhu/gorm/dialects/sqlite"
	"github.com/jinzhu/gorm"
	"database/sql/driver"
	"fmt"
)

/****************************\
    Object Layer
\****************************/

// Platform ID 
type PlatformID string

func (u *PlatformID) Scan(value interface{}) error { *u = PlatformID(value.([]byte)); return nil }
func (u PlatformID) Value() (driver.Value, error)  { return string(u), nil }

// Platform Type enumeration
type PlatformType int
const (
	PLATFORM_TYPE_NOT_A_VALUE PlatformType = iota
	PLATFORM_TYPE_TYPE1
	PLATFORM_TYPE_TYPE2 
)

var types = [...]string {
	"Not a type",
	"Type1",
	"Type2",
}

func (platform_type PlatformType) String() string {
	return types[platform_type]
}

func (u *PlatformType) Scan(value interface{}) error { *u = PlatformType(value.(int)); return nil }
func (u PlatformType) Value() (driver.Value, error)  { return int(u), nil }

// Platform descriptor.
type Platform struct {
	ID          	PlatformID			`json:"ID" gorm:"type:varchar(100);unique;not null"`				// Assigned by LCBO.
	Type        	PlatformType  		`json:"Type" gorm:"type:integer"`	
}

type PlatformStore interface {
	Init() error
	Save(platform *Platform) error
}

/****************************\
    Persist Layer
\****************************/
func NewSqlite3Store(dbname string) *gorm.DB {
	db, err := gorm.Open("sqlite3", dbname)
	if err != nil {
		panic("failed to connect database")
	}
	return db
}

type DBPlatformStore struct {
	db *gorm.DB
}

func NewDBPlatformStore(db *gorm.DB) PlatformStore {
	return &DBPlatformStore{
		db: db,
	}
}

func (store *DBPlatformStore) Init() error {
	err := store.db.AutoMigrate(&Platform{}).Error
	if err != nil {
		panic(err)
	}
	return err
}

func (store *DBPlatformStore) Save(platform *Platform) error {
	err := store.db.Create(platform).Error
	if err != nil {
		panic(err)
	}
	return err
}

/****************************\
    Application Layer
\****************************/
func main() {
	db := NewSqlite3Store("enum_test.db")
	platformStore := NewDBPlatformStore(db)
	
	fmt.Println("Initialize Database")
	err := platformStore.Init()
	if err != nil {
		panic(err)
	}
	
	platform := new(Platform)
	platform.ID = "12345"
	platform.Type = PLATFORM_TYPE_TYPE1

	platformStore.Save(platform)
}

After running the code above, I got a runtime error "sql: converting Exec argument #1's type: non-Value type int returned from Value"

]# go run enumtest.go
Initialize Database
panic: sql: converting Exec argument #1's type: non-Value type int returned from Value

goroutine 1 [running]:
panic(0x66d380, 0xc8203ae350)
        /*/panic.go:481 +0x3e6
main.(*DBPlatformStore).Save(0xc820020b20, 0xc820304500, 0x0, 0x0)
        /*/enumtest.go:84 +0x9f
main.main()
        /*/enumtest.go:106 +0x247
exit status 2

And I checked my database, the platforms table has been created successfully.

]# sqlite3 enum_test.db
sqlite> .schema platforms
CREATE TABLE "platforms" ("id" varchar(100) NOT NULL UNIQUE,"type" integer , PRIMARY KEY ("id"));

The (not-so) trivial question is how do I modify my code so that I can correctly save the entry to database.

My bigger question is: How to save a customized GO enum type to a sql database?(with a ORM engine hopefully)

答案1

得分: 13

根据当前的数据库/SQL文档,sql包有四个内置函数返回driver.Value,底层类型分别是int64float64stringbool。所以我猜这是唯一支持的四种类型。

我刚刚将枚举的底层类型从int改为int64,现在一切正常。

有问题的部分已更新为以下代码片段:

// 平台类型枚举
type PlatformType int64
const (
    PLATFORM_TYPE_NOT_A_VALUE PlatformType = iota
    PLATFORM_TYPE_TYPE1
    PLATFORM_TYPE_TYPE2 
)

var types = [...]string {
    "不是一个类型",
    "类型1",
    "类型2",
}

func (platform_type PlatformType) String() string {
    return types[platform_type]
}

func (u *PlatformType) Scan(value interface{}) error { *u = PlatformType(value.(int64)); return nil }
func (u PlatformType) Value() (driver.Value, error)  { return int64(u), nil }
英文:

According to current database/sql docs, the sql has four builtin functions that returns driver.Value, and the underlying types are int64, float64, string and bool. So I guess that's the only four types supported.

I just changed the underlying type of my enum from int to int64 and things are working.

The problematic section is updated to the following snippet:

// Platform Type enumeration
type PlatformType int64
const (
	PLATFORM_TYPE_NOT_A_VALUE PlatformType = iota
	PLATFORM_TYPE_TYPE1
	PLATFORM_TYPE_TYPE2 
)

var types = [...]string {
	"Not a type",
	"Type1",
	"Type2",
}

func (platform_type PlatformType) String() string {
	return types[platform_type]
}

func (u *PlatformType) Scan(value interface{}) error { *u = PlatformType(value.(int64)); return nil }
func (u PlatformType) Value() (driver.Value, error)  { return int64(u), nil }

huangapple
  • 本文由 发表于 2016年9月8日 06:27:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/39379928.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定