Skip to main content

Version Mode

A save command can treat the root entity's @Version either as an optimistic lock or as an ordinary assigned value. The default remains VersionMode.OPTIMISTIC_LOCK.

ModeLoaded version on updateAutomatic increment
OPTIMISTIC_LOCKAdds the implicit version checkYes, after a successful versioned update
ASSIGNMENTControlled by object shape, mask, and assignmentsNo

Use the default for concurrent editing with stale-version detection. Use ASSIGNMENT when importing externally versioned data or implementing an explicit version policy. A loaded version is then neither an implicit lock predicate nor an instruction to increment.

Assign an Incoming Version

Assume store contains a version from an external source and the values required for insertion. Only accept a newer incoming version for an existing row:

sqlClient
.saveCommand(store)
.setVersionMode(VersionMode.ASSIGNMENT)
.setUpdateWhere(
BookStoreTable.class,
(table, values) -> values.newNumber(BookStoreProps.VERSION).gt(table.version())
)
.execute();

An accepted update writes the supplied version unchanged. An older or equal version is rejected normally; inspect result acceptance. A new row is inserted independently of the update condition.

An unloaded version still receives the framework's initial value on insertion. In assignment mode, excluding a loaded version from the update mask preserves the existing version on a conflict.

Compute the Next Version

In assignment mode, @Version is also a valid target of a save assignment expression:

sqlClient
.saveCommand(store)
.setVersionMode(VersionMode.ASSIGNMENT)
.set(
BookStoreTable.class,
BookStoreProps.VERSION,
(target, values) -> target.version().plus(1)
)
.execute();

The ordinary save-assignment rules still apply: the target must be loaded and selected for update by the mask. If compare-and-increase semantics are required, add an explicit setUpdateWhere or setOptimisticLock predicate comparing the stored version with the incoming version.

caution

setVersionMode applies only to the root entity. It does not propagate to associated entities in a graph save. Switching to ASSIGNMENT removes the implicit version protection; it does not silently replace it with another check.

Insert/upsert from select uses assignment semantics for versions, so source version values do not accidentally enable optimistic locking.