The @Orm\Version annotation provides optimistic locking for ObjectQuel entities, preventing lost updates when multiple processes modify the same record concurrently.
Optimistic locking detects conflicts at commit time rather than locking records upfront. When multiple processes attempt to modify the same entity, only the first succeeds—subsequent attempts fail with a clear version mismatch error.
/**
* @Orm\Table(name="products")
*/
class ProductEntity {
/**
* @Orm\Column(name="id", type="integer", unsigned=true, primary_key=true)
* @Orm\PrimaryKeyStrategy(strategy="identity")
*/
protected ?int $id = null;
/**
* @Orm\Column(name="version", type="integer", unsigned=true)
* @Orm\Version
*/
protected ?int $version = null;
}
The @Orm\Version annotation marks a column for automatic version tracking. ObjectQuel handles all version updates automatically.
Optimistic locking prevents data loss in concurrent scenarios:
ObjectQuel supports three column types for version tracking:
// Integer version - increments by 1
/**
* @Orm\Column(name="version", type="integer", unsigned=true)
* @Orm\Version
*/
protected ?int $version = null;
// Datetime version - updates to current timestamp
/**
* @Orm\Column(name="version", type="datetime")
* @Orm\Version
*/
protected ?\DateTime $version = null;
// UUID version - generates new GUID
/**
* @Orm\Column(name="version", type="uuid")
* @Orm\Version
*/
protected ?string $version = null;
ObjectQuel automatically manages version columns during persistence:
-- ObjectQuel generates
INSERT INTO products SET name='Widget', version=1
-- ObjectQuel generates
UPDATE products
SET name='Updated Widget', version=version + 1
WHERE id=123 AND version=5
-- If version changed, zero rows affected → OrmException thrown
The WHERE clause includes the current version value. If another process already updated the record, the version won't match and the update affects zero rows, triggering an exception.