Skip to content

Concurrent edit conflicts

Status: ✅ Implemented

Two users open the same record; both edit; both save. Without protection the second save silently erases the first — the classic lost update. Enterprise apps need the second writer to know, and to choose: see the other changes, or overwrite them deliberately.

Add a @Version field (an int or long) to the entity:

public class Article implements Identifiable {
String id;
String name;
@Version @Hidden long version; // @Hidden keeps it off the form; it still travels in state
}
  • Every successful save bumps the version automatically.
  • A save carrying a version older than the stored one (someone else saved in between) is rejected: nothing is persisted and the user gets the conflict dialog — “Modificado por otro usuario” — with two choices:
    • Recargar — discard my changes and reload the record with theirs.
    • Sobrescribir — my version wins, explicitly. The save is re-dispatched with _forceOverwrite; the version keeps moving forward (the stale number is never resurrected).
  • Works out of the box on AutoCrud editors and inline row editing (@InlineEditing), where the dialog re-sends the same edited row on overwrite.
  • Entities without a @Version field are untouched — the feature is fully opt-in.

The check compares against store().findById(...) at save time. A store-managed version — a field annotated with JPA’s @jakarta.persistence.Version (or Spring Data’s @org.springframework.data.annotation.Version) — takes part in that check like Mateu’s own @Version, so a stale save gets the same dialog and Sobrescribir adopts the stored version; but Mateu does not bump it, because the persistence provider increments it itself. For a race the check cannot see, throw OptimisticLock.StaleEditException from save (e.g. translate Spring’s OptimisticLockingFailureException in your store).

  • Autosave — fewer stale windows by saving continuously
  • Audit history — Auditable records who changed what