How to Create or Update a record with GORM?

前端 未结 7 1284
悲&欢浪女
悲&欢浪女 2021-01-05 04:21

Gorm has a FirstOrCreate method and a FirstOrInit but how to check afterwards if the record was actually created? I like to create a record if it d

相关标签:
7条回答
  • 2021-01-05 04:46

    See Attrs here. It won't exactly tell you whether the record was actually created, but will let you update some fields only if record was actually created (which seems to be what you want to achieve in the end).

    0 讨论(0)
  • 2021-01-05 04:46

    There is a better way to do it:

        if err := db.Where(User{Email: "some@email.com"}).
           Assign(User{Email: "some@email.com", Age: 45}).
           FirstOrCreate(&User{}).Error; err != nil {
             c.Next(err)
             return
        }
    

    In this example, if a user with email "some@email.com" is found, then the field "Age" will be updated. On the contrary, if no user if found, then it is created.

    Note that I am discarding the created user, but you can keep the reference if you want. Also, for some GORM reasons, it is required to provide at least a filter field in the Assign clause, that's why you see email being populated twice.

    0 讨论(0)
  • 2021-01-05 04:50

    The most upvoted answer did not work for me, but this did:

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

    This works for gorm v1.9.15 and go 1.13

    0 讨论(0)
  • 2021-01-05 04:59
    func CreateOrUpdate(db *gorm.DB, model interface{}, where interface{}, update interface{}) (interface{}, error) {
        var result interface{}
        err := db.Model(model).Where(where).First(result).Error
        if err != nil {
            if !errors.Is(err, gorm.ErrRecordNotFound) {
                return nil, err
            } else {
                //insert
                if err = db.Model(model).Create(update).Error; err != nil {
                    return nil, err
                }
            }
        }
        //not update some field
        reflect.ValueOf(update).Elem().FieldByName("someField").SetInt(0)
        if err = db.Model(model).Where(where).Updates(update).Error; err != nil {
            return nil, err
        }
        return update, nil
    }
    
    0 讨论(0)
  • 2021-01-05 05:06

    update 2020.10.09

    Thanks for @vaelin

    From 1.20.x on, GORM provides compatible Upsert support for different databases( 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
    

    With gorm 1.9.x or below, it's more effecient to update first, then insert when not existed.

    // 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
        }
    }
    

    FirstOrInit and FirstOrCreate are different. If there is no match record in database, FirstOrInit will init struct but not create record, FirstOrCreate will create a record and query that record to struct.

    0 讨论(0)
  • 2021-01-05 05:07
    gormDB.Where(entity.AggregatedData{Type: v.Type}).Assign(entity.AggregatedData{Type: v.Type, Data: v.Data}).FirstOrCreate(v)
    
    
     SELECT * FROM "aggregated_data"  WHERE ("aggregated_data"."type" = '2') ORDER BY "aggregated_data"."id" ASC LIMIT 1 
    

    and if exist then

     UPDATE "aggregated_data" SET "data" = '[{"a":2}]', "type" = '2'  WHERE "aggregated_data"."id" = '2' AND (("aggregated_data"."type" = '2'))  
    

    else

    INSERT INTO "aggregated_data" ("data","type") VALUES ('[{"a":2}]','1') RETURNING "aggregated_data"."id"  
    
    0 讨论(0)
提交回复
热议问题