golang学习笔记(7)-gorm实现修改功能

gorm实现修改功能

准备工作

建立数据库连接

import (
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"log"
)

var db *gorm.DB

func OpenDB() {
	dsn := "root:adss123@tcp(127.0.0.1:3306)/go_db?charset=utf8mb4&parseTime=True&loc=Local"
	res, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	db = res
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("成功:%v\n", db)
}

建立模型

type TestTb2 struct {
	Username       string
	Password       string
	TestTb2User1ID uint
	gorm.Model
}

数据表预存数据
在这里插入图片描述

保存所有字段

利用最浅显的Save方法实现修改功能,首先查询到需要修改的记录,直接在模型上修改,并保存,实现修改功能。
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;

实验案例如下

func UpdateBySave(Any *TestTb2, id int, username string) { //查询,原数据修改,保存
	OpenDB()
	QueryOneRowById(Any, id)
	Any.Username = username
	save := db.Save(Any)
	if save.Error != nil {
		fmt.Printf("修改失败,err:%v\n", save.Error)
	} else {
		fmt.Printf("修改成功,修改后的记录为:%v\n", Any)
	}
}

更新单个列

当使用 Update 更新单个列时,你需要指定条件,否则会返回错误。当使用了 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;

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

// 根据条件和 model 的值进行更新
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;

测试案例如下

func UpdateByWhere(Any any, id int, username string) {
	OpenDB()
	update := db.Model(Any).Where("id=?", id).Update("username", username)
	if update.Error != nil {
		fmt.Printf("修改失败,err:%v\n", update.Error)
	} else {
		fmt.Printf("修改成功,修改后的记录为:%v\n", Any)
	}
}

在这里插入图片描述
在这里插入图片描述

更新多列

Updates 方法支持 struct 和 map[string]interface{} 参数。当使用 struct 更新时,默认情况下,GORM 只会更新非零值的字段。


更新单列与更新多列并不是同一方法,有拼写时有复数s的差异

// 根据 `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` 更新属性
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为目标的区别,在查询功能实现时已经有过验证,再次不做过多解释。
map为目标进行Updates实验

func UpdatesByWhere(Any any, id int, username string, password string) {
	OpenDB()
	updates := db.Model(Any).Where("id=?", id).Updates(map[string]interface{}{"username": username, "password": password})
	if updates.Error != nil {
		fmt.Printf("修改失败,err:%v\n", updates.Error)
	} else {
		fmt.Printf("修改成功,修改后的记录为:%v\n", Any)
	}
}

在这里插入图片描述

更新选定字段

如果您想要在更新时选定、忽略某些字段,您可以使用 Select、Omit
效果与查询功能实现时利用Select,Omit效果类似

// 使用 Map 进行 Select
// User's ID is `111`:
db.Model(&user).Select("name").Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})
// UPDATE users SET name='hello' WHERE id=111;

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 进行 Select(会 select 零值的字段)
db.Model(&user).Select("Name", "Age").Updates(User{Name: "new_name", Age: 0})
// UPDATE users SET name='new_name', age=0 WHERE id=111;

// Select 所有字段(查询包括零值字段的所有字段)
db.Model(&user).Select("*").Update(User{Name: "jinzhu", Role: "admin", Age: 0})

// Select 除 Role 外的所有字段(包括零值字段的所有字段)
db.Model(&user).Select("*").Omit("Role").Update(User{Name: "jinzhu", Role: "admin", Age: 0})

func UpdatesBySelect(Any any, id int, username string, password string) {
	OpenDB()
	updates := db.Model(Any).Select("username").Where("id=?", id).Updates(map[string]interface{}{"username": username, "password": password})
	if updates.Error != nil {
		fmt.Printf("修改失败,err:%v\n", updates.Error)
	} else {
		fmt.Printf("修改成功,修改后的记录为:%v\n", Any)
	}
}

批量更新

如果您尚未通过 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", "jinzhu").Error // gorm.ErrMissingWhereClause

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

db.Exec("UPDATE users SET name = ?", "jinzhu")
// UPDATE users SET name = "jinzhu"

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

测试案例如下

func UpdatesManyRows(Any any, name string, username string, password string) {
	OpenDB()
	updates := db.Model(Any).Updates(map[string]interface{}{"username": username, "password": password})
	if updates.Error != nil {
		fmt.Printf("修改失败,err:%v\n", updates.Error)
	} else {
		fmt.Printf("修改成功,修改后的记录为:%v\n", Any)
	}
}

在这里插入图片描述
修改后

func UpdatesManyRows(Any any, name string, username string, password string) {
	OpenDB()
	updates := db.Model(Any).Where("username=?", name).Updates(map[string]interface{}{"username": username, "password": password})
	if updates.Error != nil {
		fmt.Printf("修改失败,err:%v\n", updates.Error)
	} else {
		fmt.Printf("修改成功,修改后的记录为:%v\n", Any)
	}
}

在这里插入图片描述

根据子查询进行更新

使用子查询更新表

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 = ?", "jinzhu").Update("company_name", db.Table("companies as c").Select("name").Where("c.id = u.company_id"))

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

实验案例如下
在同一表下进行此操作会报错
错误代码如下:

func UpdateBySubQuery(Any any, id1 int, id2 int) {
   OpenDB()
   update := db.Model(Any).Where("id=?", id1).Update("username", db.Model(Any).Select("username").Where("id=?", id2))
   if update.Error != nil {
   	fmt.Printf("修改失败,err:%v\n", update.Error)
   } else {
   	fmt.Printf("修改成功,修改后的记录为:%v\n", Any)
   }
}

You can’t specify target table ‘test_tb2’ for update in FROM clause
(你不能在FROM子句中为更新指定目标表’test_tb2’。)
Error:
修改后:

func UpdateBySubQuery(Any1 any, Any2 any, id1 int, id2 int) {
   OpenDB()
   update := db.Model(Any1).Where("id=?", id1).Update("username", db.Model(Any2).Select("username").Where("id=?", id2))
   if update.Error != nil {
   	fmt.Printf("修改失败,err:%v\n", update.Error)
   } else {
   	fmt.Printf("修改成功,修改后的记录为:%v\n", Any1)
   }
}

使用 SQL 表达式更新

GORM 允许使用 SQL 表达式更新列,例如:

// product 的 ID 是 `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 表达式、自定义数据类型的 Context Valuer 来更新,例如:


// 根据自定义数据类型创建
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

自定义类型的构建牵扯到对Scanner与Valuer接口的实现,在后续会单独进行学习

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值