如何使用 GORM 创建或更新记录?

Tar*_*ion 12 orm go go-gorm

Gorm 有一个FirstOrCreate方法和一个FirstOrInit但是之后如何检查记录是否实际创建?如果它不存在,我喜欢创建一个记录,如果它存在,我想更新一些字段。

Bil*_*uan 17

更新 2020.10.09

感谢@vaelin

从 1.20.x 开始,GORM 为不同的数据库提供兼容的 Upsert 支持(Upsert-On-Conflict)

// Update columns to new value on `id` conflict
DB.Clauses(clause.OnConflict{
  Columns:   []clause.Column{{Name: "id"}}, // key colume
  DoUpdates: clause.AssignmentColumns([]string{"name", "age"}), // column needed to be updated
}).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
Run Code Online (Sandbox Code Playgroud)

使用 gorm 1.9.x 或以下版本,先更新,然后在不存在时插入更有效。

// update only set name=nick
if err := db.Model(&newUser).Where("id = ?", 3333).Update("name", "nick").Error; err != nil {
    // always handle error like this, cause errors maybe happened when connection failed or something. 
    // record not found...
    if gorm.IsRecordNotFoundError(err){
        db.Create(&newUser)  // create new record from newUser
    }
}
Run Code Online (Sandbox Code Playgroud)

FirstOrInit并且FirstOrCreate是不同的。如果数据库中没有匹配记录,FirstOrInit将初始化结构但不创建记录,FirstOrCreate将创建一个记录并将该记录查询到结构。

  • 这对我来说没有意义 - 为什么需要指定 where 子句来更新现有记录。如果用户对象是现有记录,则该用户对象应该已经具有 id,我希望 gorm 足够聪明,知道如果 id 存在,它应该更新。我为 Java 编写了一个类似 gorm 的库,它只需要调用 save(),无论记录是否是新的——如果它没有 id,它就会插入它,如果它有则更新。 (3认同)

nob*_*ody 6

最受好评的答案对我不起作用,但这样做了:

user := NewUser(email, password)
if db.Model(&user).Where("email = ?", email).Updates(&user).RowsAffected == 0 {
    db.Create(&user)
}
Run Code Online (Sandbox Code Playgroud)

这适用于 gorm v1.9.15 和 go 1.13

  • 也许这应该通过事务来完成,以防止数据竞争? (2认同)