11. gorm 操作要点

本文详细介绍了 Gorm 在创建、更新和删除记录时的注意事项。在创建记录时,Gorm 实现整体插入,可能导致零值覆盖默认值。更新记录时,`Save` 方法会更新所有字段,建议使用结构体或 Map 并明确指定主键来避免误操作。删除记录时,`Delete` 方法需要传入主键,否则可能误删全表。同时,提供了批量删除的示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Gorm 操作指导

在使用 gorm 时,存在一些坑,这些坑如果不注意就极易影响到整个数据库的数据,故以此文作为记录来作为使用的指导。

Create record

gorm 新建数据的方法有 Create()方法,但不能实现部分插入。它采用整体插入,struct 中声明变量都会转化为 sql 语句中的字段插入,对于未给赋值的变量采用对应类型的零值来插入。

具体例子如下:

// 声明 Users 结构
type Users struct {
    ID uint
    Email string
    Passwords string `gorm:"column:password"`
    IsFemale int // 数据库中默认值为 1
    IsActived int // 数据库中默认值为 1
}
user1 := {
  ID: 6,
  Email: "123",
}
user2 := {
  Email: "test",
  Passwords: "123",
}

当使用 Create() 方法来插入数据时

db.Create(&user2)
// generate sql is 
// UPDATE `users` SET `email` = '123', `password` = '', `is_female` = '0', `is_actived` = '0'  WHERE `users`.`id` = 6

而我们想要的 sql 为:

INSERT INTO `users` (`email`,`password`) VALUES ('test','123')

Issue:如何实现部分插入? 或避免使用 gorm 插入时,struct 中的零值覆盖默认值呢?

Answer:gorm 文档中并没有提供部分插入的实现,我们只能采取全部插入的方式,但可以使用以下方式来避免零值覆盖默认值。

方式一

// 此方法不需要显示的调用,会在程序调用 Create() 方法前自动调用
func (user *User) BeforeCreate() error {
  scope.SetColumn("IsFemale", 1)
  scope.SetColumn("IsActived", 1)
  return nil
}

方式二

// Omit() 中填入所有此次插入需要忽略的值,Users struct 中的其他值使用给定值或对应零值来更新
db.Omit("IsFemale", "IsActived").Create(&user)

Update Record

gorm 中的 Save() 方法也不是部分更新,会更新 struct 中全部的字段,未赋值的字段使用零值来更新,所以一般不建议直接使用 Save() 来更新,因为极易覆盖数据库中原有的值。

// Save will include all fields when perform the Updating SQL, even it is not changed
user1.IsFemale = 0
db.Save(&user)
// generate sql is 
// UPDATE users SET name='jinzhu 2', age=100, birthday='2016-01-01', updated_at = '2013-11-17 

更新一条记录中的多个值

  1. 使用 Struct 结构来更新(db.Model(&user).Updates(Users{...})

正确用法

db.Model(&user1).Updates(Users{IsFemale: 1, Email: "test"})
// generated sql is 
// update users set is_female = 1, email = 'test' where id = 6

错误用法Model(...) 方法中的实例没有包含主键,导致更新了所有记录(而且并不是按实例中所给的条件更新)。

db.Model(&user2).Updates(Users{IsFemale: 1, Email: "test"})
// or wanted sql: update users set is_female = 1, email = 'test' where email = '123'
// but generate sql is
// update users set is_female = 1, email = 'test'

Note:struct 类型并不能更新对应变量类型的零值

db.Model(&user1).Updates(Users{IsFemale: 0, Email: "test"})
// generate sql is 
// update users set email = 'test' where id = 6
  1. 使用 Map 结构来更新(db.Model(&user).Updates(map[string]interface{}{...})

正确用法

db.Model(&user1).Updates(map[string]interface{}{"IsFemale": 0, "Email": "test"})
// generate sql is
// update users set is_female = 0, email = 'test' where id = 6

错误用法Model(...) 方法中的实例没有包含主键,导致更新了所有记录(而且并不是按实例中所给的条件更新)。

db.Model(&user2).Updates(Users{IsFemale: 1, Email: "test"})
// or wanted sql: update users set is_female = 1, email = 'test' where email = '123'
// but generate sql is
// update users set is_female = 1, email = 'test'

更新多条记录

用法

db.Model(&Users{}).Where(&Users{Passwords:"123"}).UpdateColumns(Users{IsFemale: 1})
// generate sql is 
// update users set is_female = 1 where password = '123'
// note:struct 对零值的更新不起作用

更多 where 字句的用法详见 query

Delete Record

单条删除

使用 Delete() 方法进行单条删除时,在删除前必须确保传入主键必须存在否则会 删除整张表

db.Delete(&user1)
// gegerate sql is : delete from users where id = 6
db.Delete(&user2)
// generate sql is : delete from users

批量删除

db.Where(Users{Email: "test"}).Delete(Users{})
// generate sql is 
// delete from users where email = 'test'

更多 where 字句的用法详见 query


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值