When you enable draft handling on a RAP-managed business object, the with draft clause in your behavior definition does a lot more than the one line of syntax suggests. SAP generates a parallel draft table, wires up a technical key structure, and hands you optimistic concurrency for free — but only if you understand what's actually happening underneath.
Why drafts exist at all
Fiori Elements apps need a way to let a user start editing a record, leave the screen, come back later, and resume — without that half-finished edit being visible to anyone else or committed to the active table. RAP solves this by maintaining two parallel storage locations for every draft-enabled entity: the active table (committed, visible data) and a draft table (work-in-progress, scoped to the user who created it).
The %tky structure
Every RAP instance — active or draft — is addressed through a technical key structure called %tky. It bundles the entity's key fields together with %is_draft, a boolean that tells the framework which "version" of the instance you're pointing at. This is why the same business key can resolve to two completely different rows depending on context: one in the active table, one in the draft table, distinguished only by that flag.
ETags and concurrent edits
Optimistic locking in RAP is built on the etag master clause, typically pointed at a last-changed timestamp field:
define behavior for ZZ0193_TRAVEL alias Travel
persistent table zztravel
draft table zztravel_d
etag master LastChangedAt
{
field ( numbering : managed ) TravelID;
...
}
The annotated field — usually carrying @Semantics.systemDateTime.lastChangedAt: true — becomes the value compared on every update. If the ETag a client sends doesn't match what's currently persisted, the framework rejects the change instead of silently overwriting someone else's edit.
Where orphaned drafts come from
Orphaned drafts aren't a bug, they're an inevitable side effect of the model. A user opens a record for editing, RAP creates the draft row, and then the session just... ends. Browser crash, dropped VPN, laptop closed mid-edit. There's no explicit "discard," so the draft row sits there indefinitely with no active editor.
SAP's answer is a scheduled housekeeping job that purges drafts past a configured expiration window, rather than relying on the client to clean up after itself. It's worth checking this job is actually scheduled in your system — it's easy to enable draft handling during development and forget that production needs the cleanup job running, especially after a few months of real usage start piling up abandoned edits.