Gorm一对多关系表操作与非固定结构表数据获取

 

目录

1.简介

2.环境及表说明

3.数据库连接

4.一对多表模型定义

5.不固定模型结构的表数据获取

6.小结

参考资料:


1. 简介

在一个实际工程中需要采集一些对象的属性信息,该工程涉及多个项目,每一个项目所采集的对象属性字段各不相同且无法提前预知,需要根据项目动态设计的字段生成对应项目的采集数据表。在服务端程序开发时,团队选择了Golang,其实自己也没有用过Go语言,也就正好借着这样的机会学习学习。实施过程中选择了Gorm来进行数据库操作,虽然这个库明面上是有一个较为完善的文档,但实际使用过程中坑还真不少,本文主要介绍Gorm进行数据操作完成前叙问题的主要过程,重点解决两个关键问题:Gorm中一对多表操作以及无固定数据库模型的操作方法。

2. 环境及表说明

Golang版本为:1.14.3 windows版

Gorm版本为V1.9.14

数据库为:PostgreSQL 10

实验中的表为:

如表示意图中所示,本问题中涉及三张表,记录项目基础信息的ProjectInfo表,记录各个项目需要采集属性字段的PropsToCollect表以及根据项目所需采集字段动态创建的XXXData表。三个表中ProjectInfo表中的ProjectName和PropsToCollect表中的ProjectNameRef为相互关联的外键。

3. 数据库连接

dbConnectStr:=fmt.Sprintf("host=%s port=%d user=%s dbname=%s password=%s sslmode=disable", pgDBInfo.Host, pgDBInfo.Port, pgDBInfo.User, pgDBInfo.Name, pgDBInfo.Password)
DB, err = gorm.Open("postgres", dbConnectStr)

数据库连接过程中需要提供数据库IP、端口、用户名、数据库名、用户密码几个参数。

4. 一对多表模型定义

// PropsToCollect 用于存储工程需要采集的字段信息
type PropsToCollect struct {
   ProjectNameRef string //作为外键 如果在主表中没有指定associateForeignkey 那么必须为uint类型 不然就使用和associateForeignkey一致的字段类型
   Name           string `gorm:"column:name" json:"name"`
   Label          string `gorm:"column:label" json:"label"`
   DefaultValue   string `gorm:"column:defualtvalue" json:"defaultValue"`
}

// ProjectInfo 用于存储工程信息
type ProjectInfo struct { //这里不要用gorm.model 不然会自动加一个id 主键 导致association时出错 primary_key nil
   ProjectName     string           `gorm:"column:projectname;primary_key;index;unique;not null" json:"projectName"`
   PropsToCollects []PropsToCollect `gorm:"ForeignKey:ProjectNameRef;AssociationForeignKey:ProjectName" json:"PropsToCollects"` //这种多个元素的字段 需要把字段名字该为xxxs因为gorm会自动把表名加上s
}

根据表设计定义表模型后,表会根据模型的关联关系被关联创建,数据的录入也会默认联动(删除好像不行)。该过程中需要注意几点:

  1. 一对多的模型写法:主表通过一个字段来记录一条记录中包含的多个关联记录,该字段一般为副表模型数组,如:ProjectInfo结构体中的PropsToCollects字段;且此处需要注意,如果没有对副表模型的表名特殊处理,此处的副表字段数组应该为XXXXs,因为Gorm默认会给表名加s,如果此处字段没有s结尾,两表关联不上。
  2. 关联键映射的写法:主表中的关联键需要标记ForeignKey和AssociationForeignKey,ForeignKey为关联表中的关联键,AssociationForeignKey为主表中的关联键,如本项目中,主表模型中的ForeignKey为ProjectnameRef,AssociationForeignKey为本模型中的ProjectName,注意这里的外键其实是逻辑外键,或者本文叫的关联键
  3. 不要在主表中使用Gorm中默认的模型参数。Gorm的表模型有个gorm.model可以自动定义自增长id,插入,修改以及删除字段,且该id为主键,如果在主表中引入了gorm的默认模型参数,那数据在入库的时候会报“association primary_key nil”的错

5. 不固定模型结构的表数据获取

本文不介绍不固定模型结构的表创建,因为……emm,我是通过Gorm执行原生SQL来创建的,非固定字段的表创建其实还比较容易,但是个人觉得获取未知字段的表数据还比较值得和大家分享下。

在本项目中因为知道某项目的数据记录表中的字段数和名字,且各个字段类型都为string所以能较好的设计读取的方法,这里我不再描述如何获取所有字段数的,直接贴如何获取数据的代码:

queryStr := "SELECT * from " + extrudeTable + " WHERE entityid = ?"

rows, err := db.DB.Raw(queryStr, onePolygon.EntityID).Rows()
if err != nil {
   …
}

var dest []interface{}
dest = append(dest, new(float32), new(float32)) //其他类型示例
for i := 0; i < len(propsToCollectInProject); i++ {
    dest = append(dest, new(string))
}
for rows.Next() {  
   rows.Scan(dest...) //获取数据方法 *dest[i].(*string)
}

如代码所示,首先我用了Gorm来执行原生SQL进行查询,查询后的数据因为不知道具体的结构,所以采用interface{}数组来表达,每一个元素根据预知的类型进行初始化,然后从获取的原始数据中Scan到interface{}数组中,扫描出来的数据可以通过*dest[i].(*string)获取。

6. 小结

本文重点介绍了Gorm使用过程中一对多表的操作方法,以及在未知表结构的情况下如何从表查询结果中获取数据,该获取方法其实也适用于原生的sql包的查询结果。整体而言,在使用Gorm的过程中的感受是,该库的确能一定程度缓解一些固定范式表的操作,但是坑还是不少,且灵活性不足,所以个人在使用过程中还是将原生的SQL结合起来的;另外的一个问题是,该库写出来的代码和SQL的语句顺序不一样,长期写SQL的人可能觉得这语序怪怪的。

参考资料:

[1] https://eli.thegreenplace.net/2019/to-orm-or-not-to-orm/ 关于是否使用orm的思考

[2] https://gorm.io/docs/ grom官方文档

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值