When using OnConflict clause, im setting UpdateAll
flag to true
. My table has a Version
field also optmisticLock.Version
.
I expect gorm to update all the columns including the version column to a new version in case of a conflict but version is not getting updated automatically.
Example:
type TestEntity struct {
ID string `gorm:varchar(100);primary_key`
Name string
Version optimisticlock.Version
}
Table has one row with entries:
ID: "xyz", Name: "first", Version: 1
I want to update the current row:
testUpdateEntity := &TestEntity{
ID: "xyz",
Name: "second",
}
When i run:
dres := u.db.WithContext(context.TODO()).Clauses(clause.OnConflict{
UpdateAll: true,
}).Create(testUpdateEntity)
Then it should update version on its own to 2
after detecting the conflict.
DoUpdates
because real table has multiple columns.As I well know, GORM doesn't currently support automatically updating the optimistic lock version column when using the OnConflict clause.
When you use the OnConflict clause with UpdateAll, GORM generates an UPSERT statement that attempts to insert a new row, and if a conflict occurs, it updates all columns of the existing row with the values from the new row. However, GORM doesn't automatically handle the optimistic lock version column in this scenario.
To handle the optimistic lock version column in this situation, you can explicitly specify the columns to update using the DoUpdates clause.
Since you mentioned that your table has multiple columns and you don't want to explicitly list all of them, let try below code to dynamically generate the list of columns
// Define a function to get a list of columns to update excluding primary key and version
func getColumnsToUpdate(db *gorm.DB, entity interface{}) ([]string, error) {
var columnsToUpdate []string
// Retrieve table name
tableName := db.NamingStrategy.TableName("", db.Statement.Schema.Table)
// Retrieve column names
columnNames, err := db.Migrator().Columns(tableName)
if err != nil {
return nil, err
}
// Exclude primary key and version columns
for _, columnName := range columnNames {
if columnName != "ID" && columnName != "Version" {
columnsToUpdate = append(columnsToUpdate, columnName)
}
}
return columnsToUpdate, nil
}
then update your query
// Define update data
updateData := make(map[string]interface{})
for _, column := range columnsToUpdate {
updateData[column] = "updated_value" // Set your updated value here
}
// Add version update
updateData["Version"] = gorm.Expr("Version + 1")
// Apply update with OnConflict clause
dres := u.db.WithContext(context.TODO()).Clauses(clause.OnConflict{
UpdateAll: true,
}).Model(&TestEntity{}).Where("id = ?", testUpdateEntity.ID).Updates(updateData)