The behavior definition is the contract
Every RAP business object has a behavior definition (BDEF) — a text artifact that declares what the object can do. Which operations exist, which fields are read-only, when validations run, what actions are available.
Think of it as the contract between your business logic and everyone who consumes the object: the Fiori UI, the EML API, other RAP objects. Learn to read a BDEF fluently and RAP stops feeling mysterious.
A complete example, top to bottom
managed with draft;
define behavior for ZI_SalesOrder_TP
persistent table zsalesorder
draft table zdraft_order
lock master
authorization master ( instance )
etag master LastChangedAt
{
create;
update;
delete;
field ( readonly ) OrderID;
field ( readonly : update ) CreatedBy;
draft action Edit;
draft action Activate optimized;
draft action Discard;
draft action Resume;
draft action Prepare;
validation checkTotals on save { field NetAmount; }
validation checkCustomer on save { field CustomerID; }
determination setStatus on modify { field Status; }
determination calcTotals on modify { field NetAmount; }
action approveOrder result [1] $self;
static factory action copyOrder [1];
association _Items { create; with draft; }
}
Reading it line by line
The header — managed with draft picks the scenario. Alternatives: plain managed (no draft) or unmanaged. Everything else flows from this choice.
The entity binding — persistent table and draft table map the CDS entity to database tables. lock master declares pessimistic locking scope. authorization master ( instance ) switches on instance-based authorization checks. etag master picks the field used for optimistic concurrency.
Standard operations — create; update; delete; enables them. Omit delete and the UI won't offer deletion. The BDEF is a whitelist: unlisted operations don't exist.
If a Fiori action is mysteriously missing, check the BDEF first. Nine times out of ten, the operation was never declared.
Fields, validations, actions
Field controls — field ( readonly ) OrderID locks the field everywhere. field ( readonly : update ) allows it at creation but freezes it afterwards — the classic "number assigned once" pattern.
Draft actions — Edit, Activate optimized, Discard, Resume are the standard draft lifecycle, each declared as a draft action. Prepare runs the determinations and validations declared on save so the draft is consistent before activation. Declare them and the Fiori draft flow appears; forget them and draft silently breaks.
Validations and determinations — the on save vs on modify timing is the whole game. Validations declared on save execute during the save sequence; determinations declared on modify execute during the modify phase, as data changes. (More on placement in the validations post.)
Actions — action approveOrder result [1] $self is an instance-bound action returning the object itself. static factory action creates new instances — the "copy" or "create with template" pattern.
Syntax habits worth building
- One concern per line. BDEFs are read far more than written — vertical, explicit declarations beat compact cleverness.
- Name validations and determinations after what they check (
checkTotals, notvalidation1). Future you will thank present you. - Declare associations explicitly with their own operation sets — child entities don't inherit the parent's permissions automatically.
The BDEF looks intimidating the first week and obvious the second. It's just a contract — and contracts reward careful reading.
Which BDEF keyword took you the longest to understand? Share it in the comments.