We start with the optimistic locking concept, which is based on ETags (entity tags). To enable ETags for a model entity, add the @odata.etag annotation to an element of the entity definition.
In the example shown, the modifiedAt element from the managed aspect is defined as ETag element for both the Books entity and the Authors entity. The annotate directive is used for this, which allows existing definitions to be annotated.
Note
Elements whose content changes uniquely each time a data record is updated are suitable as ETag element. Therefore, the modifiedAt element of the predefined managed aspect is a good candidate. You could also use update counters or UUIDs, which are recalculated on each update.The idea of an ETag is to identify a specific version of an entity, in our example the version of a book or an author. This can be used to ensure the integrity of the data, as explained in the following example, without using locks.
Assume we retrieve a specific author via the following request because we want to change his or her data:
1
GET Authors(18f76942-bfb3-40c5-8300-f999f14e9cc2)
With this request, the version of the author, i.e. the value of the ETag element modifiedAt, is automatically returned via the ETag HTTP response header, for example:
1
ETag: W/"2024-03-15T11:30:48.069Z"
To write back data changed on the author, the received ETag value is used as follows in the If-Match HTTP header of the corresponding change request:
1234567
PUT Authors(18f76942-bfb3-40c5-8300-f999f14e9cc2)
If-Match: W/"2024-03-15T11:30:48.069Z"
Content-Type: application/json
{
...
}
CAP then checks whether the content of the modifiedAt element has changed in the meantime. If not, the author data is changed in the database and the modifiedAt ETag field is updated. If yes, this means that the author has been changed via another request since the data was read. CAP therefore aborts the change request and sets the status code 412 (Precondition Failed) for the HTTP response. The response body contains an error similar to the following:
12345
"error": {
"code": "412",
"message": "Precondition Failed",
"@Common.numericSeverity": 4
}