在 MySQL 中使用 GORM 插入类型为 []byte 的数据时,会出现“Error 1241: Operand should contain 1 columns(s)”错误。

3

我有一个带有类型为[]byte(密码哈希)的模型,我想使用gorm:v2将其保存在MySQL:5.7中。

// this will work
type ModelRaw struct {
    Bytes   []byte
}

type Hash []byte

// this will NOT work
type ModelTyped struct {
    Bytes Hash
}

func main() {
    // Migrate database
    // Both tables will have a column `bytes` of type `longblob default:NULL`
    if err := gormDB.AutoMigrate(&ModelRaw{}, &ModelTyped{}); err != nil {
        panic(err)
    }

    // this works
    mdl1 := &ModelRaw{Bytes: []byte("random-bytes")}
    if err := gormDB.Debug().Create(mdl1).Error; err != nil {
        panic(err)
    }

    // error here
    mdl2 := &ModelTyped{Bytes: Hash("random-bytes")}
    if err := gormDB.Debug().Create(mdl2).Error; err != nil {
        panic(err)
    }
}

上述代码会产生以下gorm的调试输出:
2020/11/06 10:31:29 /go/src/app/main.go:47
[7.715ms] [rows:1] INSERT INTO `model_raws` (`bytes`) VALUES ('random-bytes')

2020/11/06 10:31:29 /go/src/app/main.go:53 Error 1241: Operand should contain 1 column(s)
[0.926ms] [rows:0] INSERT INTO `model_typeds` (`bytes`) VALUES ((114,97,110,100,111,109,45,98,121,116,101,115))
panic: Error 1241: Operand should contain 1 column(s)

问题演示代码库: https://github.com/Iyashi/go-gorm-bytes-test

gorm:v1版本可以正常工作,而在gorm:v2版本中出现了问题。

gormAutoMigrate()方法将mysql表列创建为longblob NULL


1
为什么不想转换成字符串?GenerateFromPassword返回一个字节切片,但是这些字节都是可打印字符。 - Peter
1
我可能有点过度反应,但我担心每次将 []byte 转换/强制转换为 string 进入 mysql 都会很麻烦。对于这种情况,这样做还可以,但是应用程序未来可能会有更多的 []byte,并且在 gorm:v1 中它运行良好,因此我认为有更好的解决方案。如果没有帮助,我当然会这样做。 - Iyashi
我已经将我的 PasswordHash 类型实现为 string 并且它可以工作,但下一个 []byte 将再次失败,这是不可接受的。 - Iyashi
1
你可以为你的 Hash 类型实现 ScannerValuer 接口。示例:https://gorm.io/docs/data_types.html#Scanner-Valuer - Emin Laletovic
请展示“正常工作”的SQL生成结果;我怀疑它也是错误的。 - Rick James
显示剩余5条评论
2个回答

2

为了使其正常工作,您只需实现driver.Valuer接口:

func (h Hash) Value() (driver.Value, error) {
  return []byte(h), nil
}

那么您输入的数据将按预期与 Gorm v2 一起使用。


0

使用的值必须是字节数组,而不是数字数组。

人们可能会认为Bytes []byte等同于type Hash []byte加上Bytes Hash,但显然并非如此。

试试这个:

mdl2 := &ModelTyped{Bytes: []byte(Hash("random-bytes"))}

或者

mdl2 := &ModelTyped{Bytes: []byte{Hash("random-bytes")}}

另一个可能性是在定义Hash时摆脱struct;它似乎在效果上导致了额外的“结构化”级别。

这将迫使我为任何具有gorm的typed []byte字段的Model创建单独的struct。如果没有办法,那就算了,但我无法相信,在gorm:v1中完全相同的代码可以工作,而在gorm:v2中却停止工作。 - Iyashi
1
向gorm提交一个bug报告? - Rick James
我越来越认为这是一个错误。我会处理的。 - Iyashi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接