GORM设置模型字段创建后只读 尝试更新时抛出错误的实现方法
问题背景
需要将GORM模型的指定属性设置为创建后只读状态:现有代码通过gorm:"->;<-:create"标签已经实现了更新时字段不会被修改,但尝试更新该字段时程序会静默忽略变更,不会抛出错误,需要实现检测到非法更新时直接返回错误的效果。
核心模型定义如下:
type Product struct { gorm.Model ProductID int `gorm:"primaryKey"` Code string `gorm:"->;<-:create"` Price uint }
原有运行逻辑中,更新操作传入Code: "F42"时,数据库中Code字段会保持创建时的D4222不变,但接口返回的err为nil,无任何错误提示。
原因
GORM原生的字段读写权限标签属于SQL生成层的过滤规则:<-:create标记的字段只会在INSERT语句中被写入,生成UPDATE语句时会自动排除该字段,整个过程是静默过滤,没有内置的非法更新检测逻辑,所以不会返回错误。
实现方案
最简便的方案是利用GORM内置的BeforeUpdate钩子做字段变更校验,不需要额外引入依赖:
- 保留原有字段标签做底层兜底,避免跳过钩子时字段被意外修改
- 给模型添加
BeforeUpdate方法,检测到只读字段被变更时直接返回错误
示例代码:
import "fmt" func (p *Product) BeforeUpdate(tx *gorm.DB) error { // 检测本次更新是否尝试修改Code字段 if tx.Statement.Changed("Code") { return fmt.Errorf("Code为创建后只读字段,禁止修改") } return nil }
方案说明
tx.Statement.Changed("字段名")是GORM内置方法,无论更新时传入的是结构体参数还是map参数,即使手动用Select指定了该只读字段,都能准确识别该字段是否被纳入本次更新范围,检测逻辑可靠- 原有
gorm:"->;<-:create"标签建议保留:当使用SkipHooks: true跳过钩子执行时,标签的字段过滤规则依然生效,形成双重防护
如果项目中存在大量创建后只读的字段,可以实现GORM自定义插件统一校验:自定义一个类似create_only的结构体标签,注册更新前置回调,统一扫描当前更新语句中包含的字段,匹配到标记为创建仅写的字段时直接返回错误,减少重复的钩子代码。
验证效果
添加上述钩子后,原测试代码执行更新操作时会直接返回Code为创建后只读字段,禁止修改的错误,更新流程终止,符合预期。
内容的提问来源于stack exchange,提问作者Vishal Shivare
相关产品推荐
相关产品推荐

