gorm表初始化报错怎么办?gorm表如何实现自定义类型? | 客服服务营销数智化洞察_晓观点
       

gorm表初始化报错怎么办?gorm表如何实现自定义类型?

在开发过程中,使用GORM(Go Object-Relational Mapping)库来操作数据库是一个常见的选择,它提供了简洁的API和强大的功能,使得数据库操作更加便捷。然而,在实际应用中,开发者可能会遇到各种报错,其中之一便是关于表初始化的错误。

近期,笔者在工作中就遇到了一个关于GORM表初始化的报错,错误信息为:

invalid field found for struct xxx: define a valid foreign key for relations or implement the Valuer/Scanner interface

type Workflow struct {
        Id         int64
        Inputs     []*WorkflowInput
        CreateTime int64
        UpdateTime int64
}

type WorkflowInput struct{}

本文将详细探讨这一报错的原因、解决方法以及GORM标签(tag)的作用。

一、gorm表define a valid foreign key报错的原因是什么?

在深入探讨报错原因之前,我们首先需要了解GORM是如何处理结构体与数据库表之间的映射关系的。GORM允许开发者使用普通结构体来定义模型,这些结构体中的字段可以包含基本Go类型、指针或这些类型的别名,甚至是自定义类型。然而,当使用自定义类型时,GORM需要知道如何将该类型接收和保存到数据库,这就要求自定义类型实现database/sql包中的ScannerValuer接口。

官方文档模型定义:

模型是使用普通结构体定义的。 这些结构体可以包含具有基本Go类型、指针或这些类型的别名,甚至是自定义类型(只需要实现 database/sql 包中的ScannerValuer接口)。

因此,如果想要支持自定义的类型,就需要手动实现ScannerValuer,以便让 GORM 知道如何将该类型接收、保存到数据库。

例如:

type JSON json.RawMessage

// 实现 sql.Scanner 接口,Scan 将 value 扫描至 Jsonb
func (j *JSON) Scan(value interface{}) error {
    bytes, ok := value.([]byte)
    if !ok {
        return errors.New(fmt.Sprint("Failed to unmarshal JSONB value:", value))
    }

    result := json.RawMessage{}
    err := json.Unmarshal(bytes, &result)
    *j = JSON(result)
    return err
}

// 实现 driver.Valuer 接口,Value 返回 json value
func (j JSON) Value() (driver.Value, error) {
    if len(j) == 0 {
        return nil, nil
    }
    return json.RawMessage(j).MarshalJSON()
}

但是由于自定义结构中存在数组,不能直接写[]struct的scan方法,所以实现后仍然会报错:

unsupported Scan, storing driver.Value type []uint8 into type *[]*WorkflowInput

二、define a valid foreign key怎么解决?

针对“define a valid foreign key for relations”这一部分,我们需要考虑如何在GORM模型中正确设置外键关系以及如何为自定义类型实现这两个接口,以便GORM能够正确地将该类型与数据库中的数据类型进行映射。接下来,我们将分别介绍这两种情况的解决方法。

  1. GORM 提供了一些默认的序列化器:json、gob、unixtime。直接使用提供的默认序列化器:
type Workflow struct {
        Id         int64
        Inputs     []*WorkflowInput `gorm:"type:json;serializer:json"`
        CreateTime int64
        UpdateTime int64
}

type WorkflowInput struct{}
  1. 自定义序列化器类型,将[]*workflow.WorkflowInput看成一个整体,然后手动实现Scanner和Valuer:
type Workflow struct {
        Id         int64
        Inputs     WorkflowInputs
        CreateTime int64
        UpdateTime int64
}

type WorkflowInputs []*WorkflowInput

type WorkflowInput struct{}

三、gorm标签作用大全

了解GORM标签(tag)的作用,能帮助用户更好地利用GORM进行数据库操作。GORM标签允许开发者在结构体字段上指定额外的信息,这些信息将影响GORM如何将该字段映射到数据库中的列。通过合理使用GORM标签,开发者可以更加灵活地控制数据库表的结构和行为。

tagdesc
column指定 db 列名
type列数据类型,推荐使用兼容性好的通用类型,例如:所有数据库都支持 bool、int、uint、float、string、time、bytes
serializer指定序列化和反序列化方式,例如:json/gob/unixtime
size指定列大小,例如:size:256
primaryKey指定列为主键
unique指定列为唯一
default指定列的默认值
precision指定列的宽度,例如:浮点数float(7,2),其中precision为7,表示不包括小数点在内的列宽,即整数部分加小数部分的总长度
scale指定列中小数部分的宽度,例如:浮点数float(7,2),其中scale为2,表示浮点数的精度,多余的小数位数会被四舍五入
not null指定列为 NOT NULL
autoIncrement指定列为自动增长
autoIncrementIncrement指定列的自增步长
embedded嵌套字段
embeddedPrefix嵌入字段的列名前缀
autoCreateTime创建时追踪当前时间,对于 int 字段,它会追踪时间戳秒数,可以使用 nano/milli 来追踪纳秒、毫秒时间戳,例如:autoCreateTime:nano
autoUpdateTime创建/更新时追踪当前时间,对于 int 字段,它会追踪时间戳秒数,可以使用 nano/milli 来追踪纳秒、毫秒时间戳,例如:autoUpdateTime:milli
index根据参数创建索引,多个字段使用相同的名称则创建复合索引
uniqueIndex与 index 相同,但创建的是唯一索引
check创建检查约束,例如 check:age > 13
<-设置字段写入的权限, <-:create 只创建、<-:update 只更新、<-:false无写入权限、<- 创建和更新权限
->设置字段读的权限,->:false 无读权限
忽略该字段,- 无读写权限
comment添加字段描述信息

结语

GORM表初始化报错“invalid field found for struct xxx: define a valid foreign key for relations or implement the Valuer/Scanner interface”是一个涉及多个方面的问题。通过深入了解报错原因、掌握解决方法以及熟悉GORM标签的作用,我们可以更加高效地利用GORM进行数据库操作。希望本文能够为遇到类似问题的开发者提供一些帮助。

延展阅读:

如何用智能客服机器人提高产品复购率?电商商家怎么高效回复发货物流咨询?

淘宝2024年发展状况及未来发展趋势是什么样的?

什么是柯里化函数?柯里化函数的作用是什么?

咨询方案 获取更多方案详情                        
(0)
研发专家-芮芮研发专家-芮芮
上一篇 2024年10月27日 上午10:33
下一篇 2024年10月29日 下午2:15

相关推荐