英文:
Gorm returns Scanner error on custom string type
问题
我写了下面的实体:
type DataCategory string
const (
DataCategory1 DataCategory = "Category1"
DataCategory2 DataCategory = "Category2"
)
type Data struct {
Name string `json:"name"`
Categories []DataCategory `json:"category" gorm:"type:text[]"`
}
我手动在数据库中创建了一行,并将categories数组类型填充为Category1和Category2。
但是在读取数据时出现以下错误:
sql: Scan error on column index 19, name "category": unsupported Scan, storing driver.Value type string into type *[]DataCategory
示例Value方法:
func (s DataCategorySlice) Value() (driver.Value, error) {
if s == nil {
return nil, nil
}
if len(s) == 0 {
return "{}", nil
}
v := []string{}
for _, dc := range s {
v = append(v, string(dc))
}
result := fmt.Sprintf("{%s}", strings.Join(v, ","))
return result, nil
}
英文:
I wrote the below entity:
type DataCategory string
const (
DataCategory1 DataCategory = "Category1"
DataCategory2 DataCategory = "Category2"
)
type Data struct {
Name string `json:"name"`
Categories []DataCategory `json:"category" gorm:"type:text[]"`
}
I manually created a row in the database and filled the categories array type with Category1 and Category2.
But this gives the below error when reading the data:
sql: Scan error on column index 19, name "category": unsupported Scan, storing driver.Value type string into type *[]DataCategory
Example Value method:
func (s DataCategorySlice) Value() (driver.Value, error) {
if s == nil {
return nil, nil
}
if len(s) == 0 {
return "{}", nil
}
v := []string{}
for _, dc := range s {
v = append(v, string(dc))
}
result := fmt.Sprintf("{%s}", strings.Join(v, ","))
return result, nil
}
答案1
得分: 1
以下是翻译好的内容:
下面的示例假设您正在使用PostgreSQL作为关系数据库管理系统,并且DataCategory
的值不包含逗号或未转义的单引号。
// 声明自定义类型
type DataCategorySlice []DataCategory
// 实现driver.Valuer接口,将值编码为目标RDBMS接受的正确格式
func (s DataCategorySlice) Value() (driver.Value, error) {
if s == nil {
return nil, nil
}
if len(s) == 0 {
return []byte(`{}`), nil
}
v := []byte(`{`)
for i := range s {
v = append(v, s[i]...)
v = append(v, ',')
}
v[len(v)-1] = '}' // 用闭合括号替换最后一个逗号
return v, nil
}
// 实现scanner接口,将从数据库检索到的原始源值解码
func (s *DataCategorySlice) Scan(src any) error {
var data []byte
switch v := src.(type) {
case []byte:
data = v
case string:
data = []byte(v)
case nil:
return nil
default:
return fmt.Errorf("不支持的类型:%T", src)
}
if len(data) == 0 {
return nil
}
data = data[1:len(data)-1] // 移除周围的大括号
for _, v := range bytes.Split(data, []byte{','}) {
*s = append(*s, DataCategory(v))
}
return nil
}
或者,如果从Value() (driver.Value, error)
返回[]byte
不起作用,例如导致"ERROR: malformed array literal: <hex representation of the field's value> (SQLSTATE 22P02)"
,那么您可以尝试将返回类型更改为string
。
来自@kozhioyrin的示例
// 实现driver.Valuer接口,将值编码为目标RDBMS接受的正确格式
func (s DataCategorySlice) Value() (driver.Value, error) {
if s == nil {
return nil, nil
}
if len(s) == 0 {
return "{}", nil
}
v := []string{}
for _, dc := range s {
v = append(v, string(dc))
}
result := fmt.Sprintf("{%s}", strings.Join(v, ","))
return result, nil
}
英文:
The following example assumes that you're using PostgreSQL as the RDBMS and that the DataCategory
values do not contain commas nor unescaped single quotes.
// declare the custom type
type DataCategorySlice []DataCategory
// implement driver.Valuer to encode the value into the
// correct format that is accepted by the target RDBMS
func (s DataCategorySlice) Value() (driver.Value, error) {
if s == nil {
return nil, nil
}
if len(s) == 0 {
return []byte(`{}`), nil
}
v := []byte(`{`)
for i := range s {
v = append(v, s[i]...)
v = append(v, ',')
}
v[len(v)-1] = '}' // replace last comma with closing brace
return v, nil
}
// implement scanner to decode the raw source
// value as retrieved from the database
func (s *DataCategorySlice) Scan(src any) error {
var data []byte
switch v := src.(type) {
case []byte:
data = v
case string:
data = []byte(v)
case nil:
return nil
default:
return fmt.Errorf("unsupported type: %T", src)
}
if len(data) == 0 {
return nil
}
data = data[1:len(data)-1] // remove surrounding braces
for _, v := range bytes.Split(data, []byte{','}) {
*s = append(*s, DataCategory(v))
}
return nil
}
Alternatively, if returning []byte
from Value() (driver.Value, error)
doesn't work, e.g. it results in "ERROR: malformed array literal: <hex representation of the field's value> (SQLSTATE 22P02)"
, then you can try using string
as the return type instead.
<sub>example from @kozhioyrin</sub>
// implement driver.Valuer to encode the value into the
// correct format that is accepted by the target RDBMS
func (s DataCategorySlice) Value() (driver.Value, error) {
if s == nil {
return nil, nil
}
if len(s) == 0 {
return "{}", nil
}
v := []string{}
for _, dc := range s {
v = append(v, string(dc))
}
result := fmt.Sprintf("{%s}", strings.Join(v, ","))
return result, nil
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论