GoLong的学习之路(十七)基础工具之GORM(操作数据库)(更新Update)

news2024/11/28 9:40:48

书接上回,上回写道,GORM的查询和创建(插入数据),这回继续些增删改查的改和删的操作。

文章目录

  • 更新update
    • 修改单个列
    • 修改多个列
    • 修改选定字段
    • 批量更新新
      • 阻止全局更新
    • 使用 SQL 表达式更新
      • `注意`
    • 根据子查询进行更新
    • 不使用 Hook 和时间追踪
    • 返回修改行的数据
    • 检查字段是否有改变
    • 在 Update 时修改值
    • 其他手段更新(save)
  • 总结`注意`

更新update

修改单个列

当使用Update更新单个列时,它需要有任何条件,否则会引发错误ErrMissingWhereClause,详情查看Block Global Updates了解详细信息。当使用Model方法并且它的值有一个主值时,主键将被用来构建条件。

根据条件修改

db.Model(&User{}).Where("active = ?", true).Update("name", "hello")
// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE active=true;

当用户ID为111

// User's ID is `111`:
db.Model(&user).Update("name", "hello")
// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111;

更新条件和模型值

db.Model(&user).Where("active = ?", true).Update("name", "hello")
// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111 AND active=true;

修改多个列

Updates支持使用structmap[string]接口{}进行更新。

注意:
当使用struct进行更新时,默认情况下只更新非零字段

使用' struct '更新属性,将只更新非零字段

db.Model(&user).Updates(User{Name: "hello", Age: 18, Active: false})
// UPDATE users SET name='hello', age=18, updated_at = '2013-11-17 21:34:10' WHERE id = 111;

使用map来更新属性,或者使用Select来指定要更新的字段这种情况下

使用' map '更新属性

db.Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})
// UPDATE users SET name='hello', age=18, active=false, updated_at='2013-11-17 21:34:10' WHERE id=111;

修改选定字段

使用' map '更新字段 Select

db.Model(&user).Select("name").Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})
// UPDATE users SET name='hello' WHERE id=111;

使用' map '更新字段 Qmit

db.Model(&user).Omit("name").Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})
// UPDATE users SET age=18, active=false, updated_at='2013-11-17 21:34:10' WHERE id=111;

使用Struct 跟新字段

db.Model(&user).Select("Name", "Age").Updates(User{Name: "new_name", Age: 0})
// UPDATE users SET name='new_name', age=0 WHERE id=111;

使用Struct 更新所有字段包括非0字段

db.Model(&user).Select("*").Updates(User{Name: "李四", Role: "admin", Age: 0})
db.Model(&user).Select("*").Omit("Role").Updates(User{Name: "李四", Role: "admin", Age: 0})

更新通知(钩子)
GORM允许钩子Beforeave, BeforeUpdate, AfterSave, AfterUpdate。这些方法将在更新记录时调用。

func (u *User) BeforeUpdate(tx *gorm.DB) (err error) {
    if u.Role == "admin" {
        return errors.New("admin user not allowed to update")
    }
    return
}

批量更新新

没有使用Model指定具有主键值的记录,GORM将执行批处理更新
使用struct进行更新

db.Model(User{}).Where("role = ?", "admin").Updates(User{Name: "hello", Age: 18})
// UPDATE users SET name='hello', age=18 WHERE role = 'admin';

使用Map进行更新

db.Table("users").Where("id IN ?", []int{10, 11}).Updates(map[string]interface{}{"name": "hello", "age": 18})
// UPDATE users SET name='hello', age=18 WHERE id IN (10, 11);

阻止全局更新

如果执行一个批处理更新,没有任何条件,GORM将不会运行它,并将返回ErrMissingWhereClause错误默认

这种情况下,必须使用某些条件或使用原始SQL启用AllowGlobalUpdate模式

错误案例

db.Model(&User{}).Update("name", "李四").Error // gorm.ErrMissingWhereClause

正确但是又不怎么正确的案例,比如:where 1=1

db.Model(&User{}).Where("1 = 1").Update("name", "李四")
// UPDATE users SET `name` = "李四" WHERE 1=1

正确方法

db.Session(&gorm.Session{AllowGlobalUpdate: true}).Model(&User{}).Update("name", "李四")
// UPDATE users SET `name` = "李四"
db.Exec("UPDATE users SET name = ?", "李四")
// UPDATE users SET name = "李四"

使用 SQL 表达式更新

GORM允许使用SQL表达式更新列

// product's ID is `3`
db.Model(&product).Update("price", gorm.Expr("price * ? + ?", 2, 100))
// UPDATE "products" SET "price" = price * 2 + 100, "updated_at" = '2013-11-17 21:34:10' WHERE "id" = 3;

db.Model(&product).Updates(map[string]interface{}{"price": gorm.Expr("price * ? + ?", 2, 100)})
// UPDATE "products" SET "price" = price * 2 + 100, "updated_at" = '2013-11-17 21:34:10' WHERE "id" = 3;

db.Model(&product).UpdateColumn("quantity", gorm.Expr("quantity - ?", 1))
// UPDATE "products" SET "quantity" = quantity - 1 WHERE "id" = 3;

db.Model(&product).Where("quantity > 1").UpdateColumn("quantity", gorm.Expr("quantity - ?", 1))
// UPDATE "products" SET "quantity" = quantity - 1 WHERE "id" = 3 AND quantity > 1;

GORM还允许使用自定义数据类型更新SQL表达式/上下文值

注意

这种方式很特别

// Create from customized data type
type Location struct {
    X, Y int
}

func (loc Location) GormValue(ctx context.Context, db *gorm.DB) clause.Expr {
  return clause.Expr{
    SQL:  "ST_PointFromText(?)",
    Vars: []interface{}{fmt.Sprintf("POINT(%d %d)", loc.X, loc.Y)},
  }
}

db.Model(&User{ID: 1}).Updates(User{
  Name:  "jinzhu",
  Location: Location{X: 100, Y: 100},
})
// UPDATE `user_with_points` SET `name`="jinzhu",`location`=ST_PointFromText("POINT(100 100)") WHERE `id` = 1

根据子查询进行更新

db.Model(&user).Update("company_name", db.Model(&Company{}).Select("name").Where("companies.id = users.company_id"))
// UPDATE "users" SET "company_name" = (SELECT name FROM companies WHERE companies.id = users.company_id);

db.Table("users as u").Where("name = ?", "李四").Update("company_name", db.Table("companies as c").Select("name").Where("c.id = u.company_id"))

db.Table("users as u").Where("name = ?", "李四").Updates(map[string]interface{}{"company_name": db.Table("companies as c").Select("name").Where("c.id = u.company_id")})

不使用 Hook 和时间追踪

如果你想跳过Hooks方法并且在更新时不跟踪更新时间,你可以使用UpdateColumn UpdateColumns,它的工作原理就像update, Updates

更新单列

db.Model(&user).UpdateColumn("name", "hello")
// UPDATE users SET name='hello' WHERE id = 111;

更新多列

db.Model(&user).UpdateColumns(User{Name: "hello", Age: 18})
// UPDATE users SET name='hello', age=18 WHERE id = 111;

更新选定的列

db.Model(&user).Select("name", "age").UpdateColumns(User{Name: "hello", Age: 0})
// UPDATE users SET name='hello', age=0 WHERE id = 111;

返回修改行的数据

返回所有行

var users []User
db.Model(&users).Clauses(clause.Returning{}).Where("role = ?", "admin").Update("salary", gorm.Expr("salary * ?", 2))
// UPDATE `users` SET `salary`=salary * 2,`updated_at`="2021-10-28 17:37:23.19" WHERE role = "admin" RETURNING *

返回指定列

db.Model(&users).Clauses(clause.Returning{Columns: []clause.Column{{Name: "name"}, {Name: "salary"}}}).Where("role = ?", "admin").Update("salary", gorm.Expr("salary * ?", 2))
// UPDATE `users` SET `salary`=salary * 2,`updated_at`="2021-10-28 17:37:23.19" WHERE role = "admin" RETURNING `name`, `salary`

检查字段是否有改变

GORM提供了Changed方法,可以在Before Update Hooks(通知)中使用,它将返回字段是否更改。

Changed方法只适用于Update、Updates方法,并且它只检查Update / Updates中的更新值是否等于模型值。如果它被改变并且没有被省略,它将返回true。

func (u *User) BeforeUpdate(tx *gorm.DB) (err error) {
  // if Role changed
    if tx.Statement.Changed("Role") {
    return errors.New("role not allowed to change")
    }

  if tx.Statement.Changed("Name", "Admin") { // if Name or Role changed
    tx.Statement.SetColumn("Age", 18)
  }

  // if any fields changed
    if tx.Statement.Changed() {
        tx.Statement.SetColumn("RefreshedAt", time.Now())
    }
    return nil
}

在 Update 时修改值

要更改Before Hooks中的更新值,你应该使用SetColumn,除非它是一个完整的保存更新和保存(save)

func (user *User) BeforeSave(tx *gorm.DB) (err error) {
  if pw, err := bcrypt.GenerateFromPassword(user.Password, 0); err == nil {
    tx.Statement.SetColumn("EncryptedPassword", pw)
  }

  if tx.Statement.Changed("Code") {
    user.Age += 20
    tx.Statement.SetColumn("Age", user.Age)
  }
}

db.Model(&user).Update("Name", "李四")

其他手段更新(save)

db.First(&user)

user.Name = "jinzhu 2"
user.Age = 100
db.Save(&user)
// UPDATE users SET name='jinzhu 2', age=100, birthday='2016-01-01', updated_at = '2013-11-17 21:34:10' WHERE id=111;

Save是一个组合功能。如果save value不包含主键,它将执行Create,否则将执行Update(包含所有字段)。

db.Save(&User{Name: "jinzhu", Age: 100})
// INSERT INTO `users` (`name`,`age`,`birthday`,`update_at`) VALUES ("jinzhu",100,"0000-00-00 00:00:00","0000-00-00 00:00:00")

db.Save(&User{ID: 1, Name: "jinzhu", Age: 100})
// UPDATE `users` SET `name`="jinzhu",`age`=100,`birthday`="0000-00-00 00:00:00",`update_at`="0000-00-00 00:00:00" WHERE `id` = 1

注意
不要使用Save 关于 Model,这是一个错误用法

总结注意

在很多时候修改字段的默认值的时候会失败。其中我遇到过这样的一个情况。就是在使用更新操作的时候。
我们需要将一个非零的字段改成0,此时就出问题了。无法修改。

案例:

mysql.DB.Model(&entiy.Member{}).Where("id=", 6).Update("member_name", "0")
	mysql.DB.Model(&entiy.Member{}).Select("member_name").Where("id=?", 3).Updates(&entiy.Member{MemberName: "0"})
	mysql.DB.Model(&entiy.Member{}).Where("id = ? ", 4).Updates(map[string]interface{}{"member_name": "0"})
	mysql.DB.Save(&entiy.Member{
		MemberName: "0",
		ID:         5,
	})

运行前
在这里插入图片描述
运行后
在这里插入图片描述
可以发现6号是没有改变的。

推荐用前两种。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1166524.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Spring boot 整合 JWT

系列文章目录 第一章 Java线程池技术应用 第二章 CountDownLatch和Semaphone的应用 第三章 Spring Cloud 简介 第四章 Spring Cloud Netflix 之 Eureka 第五章 Spring Cloud Netflix 之 Ribbon 第六章 Spring Cloud 之 OpenFeign 第七章 Spring Cloud 之 GateWay 第八章 Sprin…

【WinForm详细教程六】WinForm中的GroupBox和Panel 、TabControl 、SplitContainer控件

文章目录 1.GroupBox和Panel2.TabControl3.SplitContainer 1.GroupBox和Panel GroupBox:是一个分组容器,提供一个框架将相关的控件组织在一起,它有标题、边框,但没有滚动条。 Panel:也是一个容器控件,用来…

Git GitHub同步失败

文章目录 错误解决方案第一步第二步第三步第四步第六步第七步 错误 昨天晚上提交代码到GitHub时遇到了这个错误。 remote: Support for password authentication was removed on August 13, 2021. Please use a personal access token instead.字面大体意思就是你原先的密码凭…

预约按摩小程序开发优势;

在快节奏和高压社会中,按摩已成为许多人缓解压力和保持健康的重要方式,各地的按摩店也是随处可见,而为了能够更好地提供服务,很多按摩店都引入了小程序应用。今天我们就主要了解一下按摩店小程序具体有什么用,能够提供…

【iOS免越狱】利用IOS自动化WebDriverAgent实现自动直播间自动输入

1.目标 由于看直播的时候主播叫我发 666,支持他,我肯定支持他呀,就一直发,可是后来发现太浪费时间了,能不能做一个直播间自动发 666 呢?于是就开始下面的操作。 2.操作环境 iPhone一台 WebDriverAgent …

CAD操作技巧学习总结

1&#xff0c;已知一个圆&#xff0c;画该圆切线。 L命令画直线&#xff0c;再tan指令确定第一个点为切点&#xff0c;依次输入&#xff08;长度&#xff09;<&#xff08;角度&#xff09;&#xff0c;如55<-45,负号为顺时针。 2&#xff0c;中心点偏移。 O命令偏移&am…

再学一点mybatis(原理分析)

文章目录 [TOC](文章目录) 一、mybatis是什么&#xff1f;1. Mybatis的特点以及优缺点 二、mybatis架构1.基本架构2.重要组件 三、原理1. SQL解析2. Mapper接口3. 动态代理4. SQL执行4.1 Executor4.2 StatementHandler4.3 ParameterHandler4.4 ResultHandler 文章内容有点长&am…

【蓝桥每日一题]-二分精确(保姆级教程 篇4) #kotori的设备 #银行贷款 #一元三次方程求解

今天讲二分精确题型 目录 题目&#xff1a;kotori的设备 思路&#xff1a; 题目&#xff1a;银行贷款 思路&#xff1a; 题目&#xff1a;一元三次方程求解 思路&#xff1a; 题目&#xff1a;kotori的设备 思路&#xff1a; 求&#xff1a;设备最长使用时间 二分查找&#…

Linux难学?大神告诉你,Linux到底该怎么自学!

文章目录 前言一、明白这些道理&#xff0c;Linux 就不难学二、五步学会 Linux 命令行&#xff0c;用好这本手册三、Linux 学习进阶之路 前言 知乎上有一条热门问答&#xff0c;问题是 “Linux为什么那么难&#xff1f;” 从问题来看&#xff0c;提问者还处在初学阶段。但他显…

Centos7扩容

Centos7扩容 保证虚拟机关机且没有快照的情况下按照下图进行操作&#xff1a; 设置好后开机&#xff0c;查看分区情况&#xff1a; [rootlocalhost ~]# df -h Filesystem Size Used Avail Use% Mounted on /dev/mapper/centos-root 17G 12G 5.4G 69% / …

21款奔驰GLS450升级23P驾驶辅助 智驾出行

驾驶辅助和自动驾驶的区别就是需要人为去接管&#xff0c;虽然车辆会根据道路自己行驶&#xff0c;弯道上也能居中自动修正行驶&#xff0c;长时间不接管方向盘&#xff0c;系统会提示人为接管&#xff0c;这就是奔驰的23P驾驶辅助系统&#xff0c; 很多车友升级23P驾驶辅助系…

Git统计个人提交代码行数

目录 一、git bash打开二、查看个人提交的代码行数统计三、查看项目每个人提交的代码行数统计四、查询所有用户的提交总次数五、统计用户一段时间内的提交代码量 在实际开发中&#xff0c;常常会想查看自己对于某个项目的贡献&#xff0c;管理者会查看项目下各成员的贡献&#…

mysql、clickhouse时间日期加法

mysql 在’2023-10-27 23:59:59’上增加5秒&#xff1a; SELECT DATE_ADD(2023-10-27 23:59:59, INTERVAL 5 second);clickhouse SELECT date_add(SECOND, 3, toDate(2018-01-01 00:00:00));clickhouse时间按秒、分、时、日、月、年作差 按秒&#xff1a; SELECT dateDiff…

【DataGrip使用小技巧】

在日常开发中无论是连接数据库也好&#xff0c;编写代码也好都是通过DataGrip来实现的&#xff0c;在开发过程中有一些小技巧的使用可以使开发变得高效便捷。 【非常实用】要快速查看插入符号处的表或列的文档,请按 ctrl Q(查看快速文档)。 可以显示首几行的数据&#xff0c…

团队表 -多级团队设计

团队表 -多级团队设计 user_team团队表 &#xff0c;如果存在子团队 1.我们可以通过每一个团队字段加一个parentid &#xff08;相当于一对多的关系&#xff09; 2.还可以设置一个字段CodingNum,比如这样: //系统为了管理查询团队自动生成的有序编号 可以使用3位数代表一个…

MobaXterm 连接虚拟机很慢

1. 打开配置文件 ​ vi /etc/ssh/sshd_config2. 修改配置文件 1&#xff09;修改 GSSAPIAuthentication值 为 no GSSAPIAuthentication&#xff1a;默认开启了 GSSAPIAuthentication 认证&#xff08;大多数情况下GSSAPI认证就是Kerberos认证&#xff09; 2&#xff09;取消…

聚观早报 |智界 S7将开启预售;vivo X100系列定档

【聚观365】11月3日消息 智界 S7将开启预售 vivo X100系列定档 苹果发布第四财季财报 Model 3交付范围扩大 三星Galaxy S23 FE上架 智界 S7将开启预售 据多家媒体报道&#xff0c;华为智选车业务首款轿车智界 S7 于 11 月 9 日正式开启预售&#xff0c;华为智能汽车解决方…

Python机器学习算法入门教程

机器学习&#xff08;Machine Learning&#xff0c;简称 ML&#xff09;是人工智能领域的一个分支&#xff0c;也是人工智能的核心&#xff0c;其涉及知识非常广泛&#xff0c;比如概率论、统计学、近似理论、高等数学等多门学科。 机器学习的目的是设计、分析一些让计算机可以…

JS_变量定义

定义变量 关键字var var 的作用域比较大 全局变量可以重复定义 &#xff08;变量名可以重复使用&#xff09;最下面的值算 定义方式 var a12; var b"你好"; let 定义方式 let是局部变量 在大括号里定义外面访问不了 不可以重复定义 const 定义方式 const 的…

使用 Python 进行自然语言处理第 4 部分:文本表示

一、说明 本文是在 2023 年 3 月为 WomenWhoCode 数据科学跟踪活动发表的系列文章中。早期的文章位于&#xff1a;第 1 部分&#xff08;涵盖 NLP 简介&#xff09;、第 2 部分&#xff08;涵盖 NLTK 和 SpaCy 库&#xff09;、第 2 部分&#xff08;涵盖NLTK和SpaCy库&#xf…