Hi, I have model and BeforeSave hook

func (m *User) BeforeUpdate(tx *gorm.DB) (err error) {
    tx = tx.UpdateColumn("_ver", gorm.Expr("_ver + ?", 1))
    return tx.Error
}

And save method in repository

func (repo *Repo) Save(model *User) (*User, int64, error) {
    gormDb = repo.Db // *gorm.DB
        tx := gormDb.Debug().Save(model)
    return model, tx.RowsAffected, tx.Error
}

I want save/update/persist model and apply increment for column _ver (version) on each modify.

Hook not overlap value from model now.

Expected SQL is UPDATE "users" SET "up_at"='2023-02-19 13:54:01.912',"_ver"=ver + 1,"name"='alex4' WHERE "id" = 2

Actual SQL is UPDATE "users" SET "up_at"='2023-02-19 13:54:01.912',"_ver"=23,"name"='alex4' WHERE "id" = 2

Comment From: github-actions[bot]

The issue has been automatically marked as stale as it missing playground pull request link, which is important to help others understand your issue effectively and make sure the issue hasn't been fixed on latest master, checkout https://github.com/go-gorm/playground for details. it will be closed in 30 days if no further activity occurs. if you are asking question, please use the Question template, most likely your question already answered https://github.com/go-gorm/gorm/issues or described in the document https://gorm.io ✨ Search Before Asking

Comment From: a631807682

https://github.com/go-gorm/optimisticlock

Comment From: alexpts

@a631807682 I don`t undestand how optimisticklock help me in my case. I need generate sql expression via gorm hooks. optimisticlock has not example with hook. Expression sql on Update work correct in native gorm.

Comment From: alexpts

Please reopen issue

Comment From: a631807682

tx.Statement.SetColumn("_ver", clause.Expr{SQL: tx.Statement.Quote("_ver") + "+1"}, true)

https://github.com/go-gorm/optimisticlock/blob/master/version.go#L160

Comment From: alexpts

@a631807682 this example not work for my case.

Debug sql log: UPDATE "users" SET "up_at"='2023-02-23 23:40:38.722', "_ver"=0, "name"='bob' WHERE "id" = 2

See full code from my first post. I assume that their hook changes are ignored and data for SET is taken from the .Save(model).

I work with model. My flow for edit: 1) Load model 2) Change model in process 3) Persist model

Comment From: a631807682

In fact, the setting of BeforeUpdate will be overwritten when Update later, because Save will save all values, including zero values. We can only build the complete clause through hacks. Why do you need to refer to optimisticlock.Version, because it contains custom data types and custom Clauses implementations. https://gorm.io/docs/serializer.html#content-inner https://gorm.io/docs/sql_builder.html#StatementModifier

func (m * User) BeforeUpdate(tx *gorm.DB) (err error) {
    dbname := "_ver"

    stmt := tx.Statement
    dv := reflect.ValueOf(stmt.Dest)
    if reflect.Indirect(dv).Kind() == reflect.Struct {
        selectColumns, restricted := stmt.SelectAndOmitColumns(false, true)

        sd, _ := schema.Parse(stmt.Dest, &sync.Map{}, stmt.DB.NamingStrategy)
        d := make(map[string]interface{})
        for _, field := range sd.Fields {

            if field.DBName == dbname || field.DBName == stmt.Schema.PrioritizedPrimaryField.DBName {
                continue
            }

            if v, ok := selectColumns[field.DBName]; (ok && v) || (!ok && (!restricted || !stmt.SkipHooks)) {
                if field.AutoUpdateTime > 0 {
                    continue
                }

                val, isZero := field.ValueOf(stmt.Context, dv)
                if (ok || !isZero) && field.Updatable {
                    d[field.DBName] = val
                }
            }
        }

        stmt.Dest = d
    }

    stmt.SetColumn(dbname, clause.Expr{SQL: stmt.Quote(dbname) + "+1"}, true)
    return tx.Error
}

Comment From: alexpts

Thanks!