使用GORM关联更新时跳过更新created_at字段的问题
问题解决:GORM关联更新时保持嵌套记录CreatedAt不变
问题核心
使用GORM的FullSaveAssociations更新多层嵌套关联记录时,顶层结构体的CreatedAt能保持不变,但嵌套的B、C结构体CreatedAt会被覆盖修改。原因是开启该选项后,GORM对关联记录执行INSERT ON DUPLICATE KEY UPDATE逻辑,会将结构体中携带的CreatedAt值同步回数据库。
解决方案
方案一:精准Omit忽略字段
修正之前的Omit写法,针对多层嵌套关联指定忽略路径:
txn.Session(&gorm.Session{Context: ctx, FullSaveAssociations: true}). Omit("B.CreatedAt", "B.*.C.CreatedAt"). Updates(record)
如果要忽略所有层级的CreatedAt,可以用更简洁的通配写法:
txn.Session(&gorm.Session{Context: ctx, FullSaveAssociations: true}). Omit("*.CreatedAt"). Updates(record)
该写法会让GORM在更新时自动跳过所有模型的CreatedAt字段,不影响顶层记录的原有逻辑。
方案二:调整结构体标签(修正之前的尝试)
给嵌套结构体的CreatedAt添加<-:create标签,明确该字段仅在创建时写入,更新时忽略:
struct B { ID string `gorm:"column:id;type:char(36); not null;primary_key"` AID string `gorm:"column:aid;type:char(36); not null"` C []*C `gorm:"foreignKey:BID;references:ID"` CreatedAt time.Time `gorm:"column:created_at;type:timestamp; not null;<-:create"` UpdatedAt time.Time `gorm:"column:updated_at;type:timestamp; not null"` } struct C { ID string `gorm:"column:id;type:char(36); not null;primary_key"` BID string `gorm:"column:bid;type:char(36); not null"` CreatedAt time.Time `gorm:"column:created_at;type:timestamp; not null;<-:create"` UpdatedAt time.Time `gorm:"column:updated_at;type:timestamp; not null"` }
若之前测试失败,需检查单元测试的预期是否匹配该标签的行为,或排查其他关联配置问题。
方案三:Select指定允许更新的字段
通过Select明确列出所有可更新的字段,排除CreatedAt:
txn.Session(&gorm.Session{Context: ctx, FullSaveAssociations: true}). Select("UpdatedAt", "B", "B.UpdatedAt", "B.C", "B.C.UpdatedAt"). Updates(record)
此方式适合字段较少的场景,需确保所有需要更新的业务字段都被包含在内。
验证效果
配置完成后,关联记录的SQL会变为:
INSERT INTO `B` (`id`, `aid`, `updated_at`) ON DUPLICATE KEY UPDATE `updated_at`=VALUES(`updated_at`)
不再包含created_at的更新逻辑,从而保留原始创建时间。
内容的提问来源于stack exchange,提问作者Hemant
相关产品推荐
相关产品推荐

