将枚举值保存到数据库
Posted
技术标签:
【中文标题】将枚举值保存到数据库【英文标题】:Saving enumerated values to a database 【发布时间】:2014-08-07 12:08:01 【问题描述】:我是 Go 新手,我正在尝试编写一个小程序来中。 我声明我的价值观的方式如下:
type FileType int64
const (
movie FileType = iota
music
book
etc
)
我在结构中使用这些值,如下所示:
type File struct
Name string
Type FileType
Size int64
我将 gorp 用于我的数据库内容,但我想 gorp 的使用与我的问题无关。我把东西放在我的数据库中是这样的:
dbmap.Insert(&File"MyBook.pdf",movie,1000)
但是当我尝试检索东西时……
dbmap.Select(&dbFiles, "select * from Files")
我收到以下错误:
panic: reflect.Set: value of type int64 is not assignable to type main.FileType
当我使用 int64
作为 const(...)
和 File.Type
字段的类型时,一切正常,但我是 Go 新手,想了解问题所在。
在我看来,我有两个问题:
-
为什么 Go 不能成功转换这些东西?我查看了 Go 反射和 sql 包的源代码,并且有这种转换的方法,但它们似乎失败了。这是一个错误吗?有什么问题?
我发现,可以通过实现以下方法来实现sql.Scanner
接口:
Scan(src interface) error
我尝试实现该方法,我什至能够从src
获得正确的值并将其转换为FileType
,但我很困惑是否应该为“(f *FileType)
或@987654334 实现该方法@. 无论哪种方式,方法都会被调用,但是我无法覆盖 f
(或者至少更新稍后会丢失),并且从数据库读取的 File
实例始终具有“0”作为 @ 的值987654337@.
你对这两点有什么想法吗?
【问题讨论】:
你真的不应该使用 Go 范围之外的 iota 值,例如数据库。如果您曾经对常量重新排序,或者在中间添加一个新常量,iota 值将发生变化,与数据库中的现有记录不匹配。 【参考方案1】:我最近也有同样的需求,解决方法是实现两个接口:
-
sql/driver.Valuer
sql.Scanner
这是一个工作示例:
type FileType int64
func (u *FileType) Scan(value interface) error *u = FileType(value.(int64)); return nil
func (u FileType) Value() (driver.Value, error) return int64(u), nil
【讨论】:
这是正确的答案,应该被接受。干得好。 出于好奇,我完全是新手。有充分的理由将其设为 int64 吗?似乎您只需要一个 int16 甚至 int8,因为您可能不会有数十亿个可能的值。 @bigblind 这是原始问题使用的内容。我通常不会开始过多担心值大小,直到它成为一个问题,或者问题空间需要它。【参考方案2】:有点离题,但可能对其他人有用,因为在使用 golang 中的 postgres 枚举字段(以字节形式返回)时,我在解决类似问题时不断重新审视这个问题/答案。
// Status values
const (
incomplete Status = "incomplete"
complete Status = "complete"
reject Status = "reject"
)
type Status string
func (s *Status) Scan(value interface) error
asBytes, ok := value.([]byte)
if !ok
return errors.New("Scan source is not []byte")
*s = Status(string(asBytes))
return nil
func (s SubjectStatus) Value() (driver.Value, error)
// validation would go here
return string(s), nil
【讨论】:
Go 没有enum
s。您的常量是string
类型。如果您希望它们的类型为 Status
(您可以),那么您应该使用 Incomplete Status = "incomplete"
、Complete Status = "complete"
等(此外,全大写标识符不是惯用的 Go)。
@DaveC 谢谢,更新了!为了清楚起见,我指的是 postgres 的实际 enum
列类型,但很好的更正。【参考方案3】:
-
Go 需要特定类型,这有时会很痛苦。
对于“原生”类型,
(f FileType)
比 (f *FileType)
便宜,除非你有一个复杂的类型,否则最好不要使用指针。
什么意思它不会覆盖它?修改后是否重新保存了结构?
【讨论】:
关于 2:好的,但是当我在 Scan 方法中编写类似“f = book”的内容时,如何更改“f”以防“(f FileType)”,它没有效果。 您只能修改您的值,如果它在指针接收器上运行。看看stdlib中sql.NullInt64
的实现。以上是关于将枚举值保存到数据库的主要内容,如果未能解决你的问题,请参考以下文章