直接回答:GORM 保存对象时会连带自动创建关联的子对象,如果不想要这种行为,就得在 BeforeCreate 钩子里自己判断处理,或者关掉关联的自动保存。
关于多对多,插入对象,子对象会自动创建的问题
,将子对象的BeforeCreate钩子里进行一次,判断,如果id>0那么就查询下数据库,将数据库的值给到对象,如果查询不到就报错
1 | func (entity *User) BeforeCreate(tx *gorm.DB) (err error) { |
实体对象在数据库不能为空,则需要类型为引用类型,否则可能传入空字符串或者0值
可以为引用类型的目的是为了能设置为0,false,空字符串,如果数据库里允许有零值,就应该用引用类型,比如姓名,如果不是引用类型,更新的话也不会将数据库改为空
Model()函数什么时候用
对于查询来说,一般使用Find,First就够了。当查询链中没有用到Find,First等函数时,这时就无法指定要查询的表了,此时就要用Model来指定表。
更新的函数的参数是字段值,不能确定是哪个表,这时候也需要用到Model
使用Model还能指定查询条件,但是这个条件只能是id,不能使用其他条件
table和select不能和Find一起用,因为Find本身就带有指向表和查找表中字段的sql语句
Join Preload适用于一对一的关系,例如:has one, belongs to
在product模型中关联image表的时候使用belongsTo,因为此时外键img_id字段,在做为主表的product中。
在image模型中关联product表的时候使用hasOne,因为此时外键img_id字段,在做为从表的product中。
简单说,使用belongsTo还是hasOne,就看外键是处于当前模型的主表还是从表中。 ———————————————— 版权声明:本文为CSDN博主「小呆瓜与小胖妞」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/weixin_42854221/article/details/82918028
关于预加载Preload 结果是嵌套
Find谁就是把谁都取出来,然后看Preload的谁在find的结果里
1 | type DataNode struct { |
关于关联Association 结果是列表
取出一个user,看都哪个languages属于这个user,跟上面那个的区别就是这个是列表,上面的是嵌套
类似于右链接,Preload类似于左链接
1 | db.Model(&user).Association("Languages").Find(&languages) |
子查询
1 |
|
立即执行方法
Create,First,Find,Take,Save,UpdateXXX,Delete,Scan,Row,Rows
上面的方法会立即生成sql语句,并进入数据库进行操作
默认值
您可以通过标签 default 为字段定义默认值,如:
1 | type User struct { |
插入记录到数据库时,默认值 会被用于 填充值为 零值 的字段
注意 对于声明了默认值的字段,像
0、''、false等零值是不会保存到数据库。您需要使用指针类型或 Scanner/Valuer 来避免这个问题,例如:
1 | type User struct { |
注意 若要数据库有默认、虚拟/生成的值,你必须为字段设置
default标签。若要在迁移时跳过默认值定义,你可以使用default:(-),例如:
1 | type User struct { |
使用虚拟/生成的值时,你可能需要禁用它的创建、更新权限,查看 字段级权限 获取详情
创建时
字段不写,或者是0值,那么会在sql语句中排除掉,使用默认值(默认的默认值就是0值),默认值可以自定义
查询时
1 | // 有效,因为通过 `db.Model()` 指定了 model |
注意 当使用struct作为条件查询时,GORM 只会查询非零值字段。这意味着如果您的字段值为 0、''、false 或其他 零值,该字段不会被用于构建查询条件,用where构建字符串可以避免
更新时
注意 当通过 struct 更新时,GORM 只会更新非零字段。 如果您想确保指定字段被更新,你应该使用 Select 更新选定字段,或使用 map 来完成更新操作
更新选定字段
如果您想要在更新时选定、忽略某些字段,您可以使用 Select、Omit
1 | // 使用 Map 进行 Select |
更新为null
**数字**想要某项更新为null需要用Select选中需要更新的字段,传个nil就可以更新为空了,因为nil不确定是传了nil还是没传所以为nil,所以需要单独的接口去处理更新为null的问题
整体,不论数字还是字符串,应该在接收的时候,全部采用指针,这样才能知道是传了0值还是没传值
在数据库更新阶段只更新非nil的字段,结构体更新的时候需要用指针,这样才能将0值更新进去
实体对象字段为指针,如果修改的时候实体不传值,就会被更新为空,实体对象中的nil要慎用
更新阶段非必填要用引用接收,需要知道是传了还是没传,只要传的都要更新进去
查询阶段,非必填字段接收用引用,如果不是nil就用where构建
修改默认id类型
1 | func (u *YS) BeforeCreate(*gorm.DB) (err error) { |
这里用的钩子,在创建的时候通过雪花算法获取的id
每个设备的每个通道会有多个需要判断的事件
订阅中收到设备id,就组合通道从下面表里去查询,预算,查不到写入日志“某设备的某通道没有预警方案”
运算的时候出错也写入日志“某设备某通道的预警方案id运算时候出错”
预警报警key-->
设备id+通道名称:预警方案列表
1 | docker run -d --name=webdav-aliyundriver --restart=always -p 49157:8080 -v /etc/localtime:/etc/localtime -v /volume2/docker/Aliyun/:/etc/aliyun-driver/ -e TZ="Asia/Shanghai" -e ALIYUNDRIVE_REFRESH_TOKEN="替换成你自己的 token" -e ALIYUNDRIVE_AUTH_PASSWORD="******" -e JAVA_OPTS="-Xmx1g" zx5253/webdav-aliyundriver |
这篇笔记整理自我自己的实践记录,如果做法有出入,或者你踩过别的坑,欢迎到留言板一起聊聊。