英文:
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
类型的值。修改PlatformType
的Value
方法如下:
func (u PlatformType) Value() (driver.Value, error) {
return int64(u), nil
}
另外,你还需要在PlatformType
的Scan
方法中将值转换为PlatformType
类型。修改PlatformType
的Scan
方法如下:
func (u *PlatformType) Scan(value interface{}) error {
*u = PlatformType(value.(int64))
return nil
}
通过这些修改,你应该能够正确保存枚举类型的值到数据库中。
至于你更大的问题,即如何将自定义的GO枚举类型保存到SQL数据库中(最好使用ORM引擎),你已经在代码中使用了gorm作为ORM引擎,这是一个很好的选择。你只需要按照上述修改的方式,为你的自定义枚举类型实现Value
和Scan
方法,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
,底层类型分别是int64
、float64
、string
和bool
。所以我猜这是唯一支持的四种类型。
我刚刚将枚举的底层类型从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 }
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论