Golang|Gorm如何实现CreateOrUpdate?

前言

在数据库的CURD过程中,我们偶尔会遇到这样的需求,一条记录发到后端,如果已经存在,就更新这条记录,如果不存在,就插入这条数据。比如我遇见的这个云同步便签的功能,

用户点击保存会有两种情况,一是新建的便签,二是已有的标签经过编辑后保存,所以我们希望在同一个接口兼容这两种操作。

如何实现?

如果正常来说,我第一个想到的是这样

func CreateOrUpdateRecord(db *gorm.DB, record *models.Record) error {
    // 尝试在数据库中查找具有相同 record_id 的记录
    existingRecord := &models.Record{}
    result := db.Where(models.Record{RecordID: record.RecordID}).FirstOrCreate(existingRecord)
    if result.Error != nil {
        return result.Error
    }

    // 如果记录已存在,更新它的字段
    if !result.RowsAffected == 0 {
        existingRecord.Title = record.Title
        existingRecord.Content = record.Content
        result := db.Save(existingRecord)
        if result.Error != nil {
            return result.Error
        }
    }

    return nil
}

这不优雅!

所以我去查了一下官方文档中关于这种操作的说明,在这里,官方给出的解释是这样的。

// Update columns to new value on `id` conflict
db.Clauses(clause.OnConflict{
  Columns:   []clause.Column{{Name: "id"}},
  DoUpdates: clause.AssignmentColumns([]string{"name", "age"}),
}).Create(&users)
// MERGE INTO "users" USING *** WHEN NOT MATCHED THEN INSERT *** WHEN MATCHED THEN UPDATE SET "name"="excluded"."name"; SQL Server
// INSERT INTO "users" *** ON CONFLICT ("id") DO UPDATE SET "name"="excluded"."name", "age"="excluded"."age"; PostgreSQL
// INSERT INTO `users` *** ON DUPLICATE KEY UPDATE `name`=VALUES(name),`age`=VALUES(age); MySQL

可惜的时这部分并没有官方的中文翻译,找了好一会,这里使用Clauses 方法:用于指定查询的选项和条件,之后添加了一个错误处理的配置和解决参数,这里需要一个唯一约束的键作为冲突的判断,当然,并不一定是主键才可以,我们可以通过unique标签来选定任意键唯一约束。

// 便签表
type Record struct {
	gorm.Model
	RecordID int64  `json:"record_id" gorm:"unique"`
	UserID   int64  `json:"userID"`
	Title    string `json:"title"`
	Content  string `json:"content"`
}

下面的参数是当冲突发生时,给出的解决方案。

  • DoNothing:冲突后不处理,参照上面的 Build 实现可以看到,这里只会加入 DO NOTHING;
  • DoUpdates: 配置一批需要赋值的 KV,如果没有指定 DoNothing,会根据这一批 Assignment 来写入要更新的列和值;
  • UpdateAll: 冲突后更新所有的值(非 default tag字段)。

变得优雅

于是,这个操作就变成了下面的样子,如果没有唯一索引的限制,我们就无法复用这个能力,需要考虑别的解法。

func CreatOrUpdateRecord(record *models.Record) error {
	return db.Clauses(clause.OnConflict{
		Columns:   []clause.Column{{Name: "record_id"}},
		UpdateAll: true,
	}).Create(record).Error
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇