基于XORM实现嵌入结构体:解决级联键异常及增改查问题
问题描述
尝试实现支持XORM的嵌入结构体时,持续遇到级联键类异常错误,现咨询正确实现方式,同时询问如何检索该结构体对象、更新其中的JSON字段。相关代码示例如下:
type Profile struct { PortalLanguage string `json:"portalLanguage"` PortalAutoLaunch bool `json:"portalAutoLaunch"` PortalDefaultApp string `json:"portalDefaultApp"` } type UserProfile struct { Id int `xorm:"int autoincr" json:"id"` Owner string `xorm:"varchar(100) notnull index pk" json:"owner"` Name string `xorm:"varchar(100) notnull pk" json:"name"` profile *Profile `xorm:"jsonb" json:"profiles"` }
检索对象代码:
adapter.engine.Get(&profile)
更新JSON字段代码:
adapter.engine.ID(core.PK{owner, name}).Update(profile)
解决方案
1. 修复结构体定义(解决级联键异常)
代码存在两个核心问题导致级联键错误:
- 字段未导出:
profile是小写开头,XORM无法识别未导出的结构体字段,会引发映射异常,需改为大写Profile。 - 复合主键一致性:
Owner和Name均标记为pk构成复合主键,需确保后续检索、更新操作时主键值正确传入。
修正后的结构体:
type Profile struct { PortalLanguage string `json:"portalLanguage"` PortalAutoLaunch bool `json:"portalAutoLaunch"` PortalDefaultApp string `json:"portalDefaultApp"` } type UserProfile struct { Id int `xorm:"int autoincr" json:"id"` Owner string `xorm:"varchar(100) notnull index pk" json:"owner"` Name string `xorm:"varchar(100) notnull pk" json:"name"` // 改为可导出字段,xorm标签指定jsonb类型(仅PostgreSQL支持,MySQL可改为xorm:"json") Profile *Profile `xorm:"jsonb" json:"profiles"` }
2. 正确检索结构体对象
检索时需通过主键定位记录,两种常用方式:
方式一:通过实例匹配主键
var profile UserProfile // 设置要检索的主键值 profile.Owner = "目标owner值" profile.Name = "目标name值" // 执行检索 err := adapter.engine.Get(&profile) if err != nil { // 处理错误逻辑 } // 检索成功后,profile.Profile即为解析后的JSON结构体
方式二:通过Where条件检索
var profile UserProfile err := adapter.engine.Where("owner = ? AND name = ?", "目标owner值", "目标name值").Get(&profile) if err != nil { // 处理错误逻辑 }
3. 更新JSON字段
更新JSON字段有两种常用方式,按需选择:
方式一:更新整个JSON结构体
先检索对象,修改JSON字段内容后执行更新:
var profile UserProfile profile.Owner = "目标owner值" profile.Name = "目标name值" err := adapter.engine.Get(&profile) if err != nil { // 处理错误逻辑 } // 修改JSON字段内的属性 profile.Profile.PortalLanguage = "zh-CN" profile.Profile.PortalAutoLaunch = true // 通过复合主键定位记录并更新 err = adapter.engine.ID(core.PK{profile.Owner, profile.Name}).Update(&profile) if err != nil { // 处理错误逻辑 }
方式二:更新JSON字段内单个属性(数据库原生语法)
如果仅需更新JSON内的某个属性,可直接用数据库JSON函数操作,避免检索整个对象:
- PostgreSQL示例:
// 更新Profile中的PortalLanguage字段 _, err := adapter.engine.Exec("UPDATE user_profile SET profile = jsonb_set(profile, '{portalLanguage}', ?) WHERE owner = ? AND name = ?", `"zh-CN"`, "目标owner值", "目标name值") if err != nil { // 处理错误逻辑 }
- MySQL示例:
// 更新Profile中的PortalLanguage字段 _, err := adapter.engine.Exec("UPDATE user_profile SET profile = JSON_SET(profile, '$.portalLanguage', ?) WHERE owner = ? AND name = ?", "zh-CN", "目标owner值", "目标name值") if err != nil { // 处理错误逻辑 }
额外注意事项
- 确保数据库表结构与结构体匹配:
user_profile表需包含id(自增int)、owner(varchar(100)非空主键)、name(varchar(100)非空主键)、profile(jsonb/json类型)字段。 - 可使用XORM自动建表功能同步结构:调用
adapter.engine.Sync2(new(UserProfile))生成匹配表结构,避免手动建表错误。
内容的提问来源于stack exchange,提问作者Bad Boy
相关产品推荐
相关产品推荐

