在 mysql 中使用 gorm 插入类型 []byte 引发 "Error 1241: Operand should contain 1 columns(s)"

Insert typed []byte with gorm in mysql raises "Error 1241: Operand should contain 1 columns(s)"

我有一个类型为 []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 闯入。

gorm 的 AutoMigrate() 创建 mysql table 列作为 longblob NULL.

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

有人会认为 Bytes []byte 相当于 type Hash []byte 加上 Bytes Hash,但显然不是。

试一试:

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

或者也许

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

另一种可能是去掉Hash定义中的struct;它似乎导致了额外的“结构化”效果。

为此,您应该只实现一个 driver.Valuer 接口:

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

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