Skip to content

Lesson 17 — RAP Draft ​

Lesson 16 exposed the Reservation Business Object as an:

text
OData V4 UI service

The service already reuses:

text
managed CRUD
determinations
validations
messages
actions
feature control
authorization
DCL

But the editing model is still non-draft.

Today you add:

text
RAP Draft

Draft changes the transactional user experience.

Instead of requiring one interaction to remain inside one short ABAP transaction, a draft can be persisted temporarily and resumed across requests and sessions.

The architecture becomes:

text
Fiori Elements
      ↓
OData V4 UI
      ↓
Draft-enabled Projection
      ↓
Draft-enabled RAP BO
   ┌───────────────┐
   │               │
Active Table    Draft Table
 ZRESV_###      ZDRESV_###
   │               │
   └──── Activate ─┘

Lesson information ​

Teacher-led timeAbout 3 hours
Self-practice timeAbout 3 hours
EnvironmentSAP BTP ABAP Trial
PrerequisiteLesson 16
Base BOZR_RESERVATION_###
Active tableZRESV_###
Draft tableZDRESV_###
ProjectionZC_RESERVATION_###
ServiceExisting Lesson 16 OData V4 UI service
Draft typeExclusive draft
Total ETagLastChangedAt
Main outcomeCreate, edit, validate, save, resume, and discard persistent drafts

Replace:

text
###

with your own student/group suffix.


Learning objectives ​

After the teacher-led part, you should be able to:

  • explain why RAP Draft exists;
  • distinguish business Status from RAP draft state;
  • distinguish active data from draft data;
  • explain new-draft vs edit-draft;
  • explain why a draft table is required;
  • generate a draft table with ADT Quick Fix;
  • explain the draft administration include conceptually;
  • enable exclusive draft with with draft;
  • configure draft table;
  • explain why a total ETag is mandatory for a draft BO;
  • use LastChangedAt as total ETag;
  • distinguish local ETag from total ETag;
  • declare Edit, Activate, Discard, Resume, and Prepare;
  • use Activate optimized;
  • assign existing on-save validations to Prepare;
  • explain how Prepare protects activation;
  • default ResponsibleUser for a new draft;
  • adapt global and instance authorization for draft actions;
  • add use draft to the projection BDEF;
  • reuse all draft actions in strict projection behavior;
  • explain durable draft locks;
  • inspect active and draft persistence separately;
  • prove that an unsaved draft does not overwrite active persistence;
  • prove that Discard removes draft changes;
  • prove that invalid draft data cannot activate;
  • explain the Fiori Elements Edit / Save / Cancel workflow;
  • explain what activation does to the active and draft tables.

Draft Concept ​

1. Why normal transactions are not enough for UI editing ​

A normal RAP transaction is intentionally short.

Lesson 12 used:

text
MODIFY
READ
COMMIT

inside one ABAP consumer flow.

A human UI session is different.

A user may:

text
open an object
edit several fields
navigate away
return later
save after several requests

The editing work needs durable intermediate storage.

That is what draft provides.


2. What is a RAP draft? ​

A draft is a persisted intermediate version of BO data.

It is stored separately from active business data.

text
Active instance
→ business data currently active

Draft instance
→ work in progress

Draft handling lets an editing transaction span:

text
multiple HTTP requests
multiple ABAP sessions
human think time

3. Draft is not a Status value ​

Do not confuse:

text
Status = N

with:

text
draft

N = New is business state.

Draft is framework-managed editing state.

A Reservation can be:

text
business Status = N
active

or:

text
business Status = N
draft

These are different dimensions.


4. Active and draft persistence ​

Before Lesson 17:

text
ZRESV_###
→ active business data

After Lesson 17:

text
ZRESV_###
→ active business data

ZDRESV_###
→ draft business data + draft runtime administration

Do not manually treat the draft table as an application table.

The RAP draft runtime owns it.


5. Two draft scenarios ​

New draft ​

There is:

text
draft instance

but no corresponding active instance yet.

Typical UI trigger:

text
Create

Edit draft ​

An active instance already exists.

RAP copies it into the draft table for editing.

Typical UI trigger:

text
Edit

Total ETag ​

6. Local ETag vs total ETag ​

You already use:

text
LocalLastChangedAt

as:

text
etag master

That protects normal optimistic concurrency for the entity.

Draft also requires:

text
total ETag

for the whole lock-master BO.


7. Why total ETag exists ​

An edit draft can live longer than a normal lock lifetime.

RAP needs to know:

Has the active version changed since this draft was created?

The total ETag lets RAP detect an outdated draft.


8. Use LastChangedAt ​

Your root CDS already marks:

text
LastChangedAt

with:

abap
@Semantics.systemDateTime.lastChangedAt: true

This is the correct existing field to use as:

text
total etag

No new timestamp is required.


Harden Ownership for Draft Creation ​

9. Why Lesson 15 ownership needs one refinement ​

Lesson 15 allowed the external create request to provide:

text
ResponsibleUser

That was useful for testing:

text
owned vs unassigned

A Fiori draft create should not depend on the user manually entering their technical user ID before authorization becomes meaningful.

So Lesson 17 makes ownership system-derived.


10. Make ResponsibleUser read-only ​

Change:

abap
field ( readonly:update ) ResponsibleUser;

to:

abap
field ( readonly ) ResponsibleUser;

External consumers no longer assign ownership.

The BO determines it.


11. Add setResponsibleUser ​

Declare:

abap
determination setResponsibleUser on modify { create; }

The rule:

text
new instance
→ ResponsibleUser = current technical user

This applies to:

text
new draft create
normal EML create

12. Implement owner determination ​

Use:

abap
METHOD setResponsibleUser.

  READ ENTITIES OF ZR_Reservation_### IN LOCAL MODE
    ENTITY Reservation
      FIELDS ( ResponsibleUser )
      WITH CORRESPONDING #( keys )
    RESULT DATA(reservations).

  DATA updates TYPE TABLE FOR UPDATE ZR_Reservation_###.

  DATA current_user TYPE abp_creation_user.
  current_user = cl_abap_context_info=>get_user_technical_name( ).

  LOOP AT reservations INTO DATA(reservation)
    WHERE ResponsibleUser IS INITIAL.

    APPEND VALUE #(
      %tky            = reservation-%tky
      ResponsibleUser = current_user
    ) TO updates.

  ENDLOOP.

  IF updates IS NOT INITIAL.

    MODIFY ENTITIES OF ZR_Reservation_### IN LOCAL MODE
      ENTITY Reservation
        UPDATE FIELDS ( ResponsibleUser )
        WITH updates.

  ENDIF.

ENDMETHOD.

The provider may fill a read-only field through local-mode EML.


Enable Draft in the Base BDEF ​

13. Add with draft ​

Open the base Behavior Definition.

After:

abap
strict ( 2 );

add:

abap
with draft;

This draft-enables the whole BO.


14. Draft applies to the BO, not one random field ​

with draft is a BO-level capability.

It does not mean:

text
Status becomes draft

or:

text
one field is drafted

The RAP BO participates in the draft lifecycle.


15. Add the draft table ​

After:

abap
persistent table zresv_###

add:

abap
draft table zdresv_###

At first, ZDRESV_### does not exist.

That is intentional.


16. Generate the draft table with Quick Fix ​

Place the cursor on:

text
zdresv_###

Use:

text
Ctrl+1

Choose the Quick Fix equivalent to:

text
Create draft table ZDRESV_### for entity ZR_RESERVATION_###

Let ADT generate the table.

Do not manually guess the draft table structure.


17. Inspect the generated draft table ​

The generated draft table contains:

text
one storage field for relevant root view elements
+
technical draft-administration information

The RAP runtime uses the technical draft fields to manage the draft lifecycle.

Activate the generated table.


18. Do not hand-maintain the draft table ​

The draft table is:

text
runtime persistence

not:

text
normal business-maintenance persistence

Do not:

text
INSERT
UPDATE
DELETE

draft rows manually.

Use RAP Draft.


19. Add total ETag ​

Change:

abap
lock master

to:

abap
lock master
total etag LastChangedAt

The total ETag must immediately follow the lock-master definition in the BDEF structure.


20. Keep the local ETag ​

Also keep:

abap
etag master LocalLastChangedAt

Now the BO has:

text
LocalLastChangedAt
→ local/entity ETag

LastChangedAt
→ total ETag for draft concurrency

Both have distinct roles.


Draft Actions ​

21. Draft actions are framework operations ​

Draft-enabled BOs have a standard draft lifecycle.

The important actions are:

text
Edit
Activate
Discard
Resume
Prepare

These are not your business actions:

text
confirm
cancel

They belong to the RAP draft framework.


22. Edit ​

Edit creates an edit draft from an active instance.

Flow:

text
active row
   ↓ Edit
active row stays
+
draft copy created

The active row is not overwritten merely because editing started.


23. Activate ​

Activate transfers valid draft changes into active data.

For an edit draft:

text
draft
→ UPDATE active
→ draft removed

For a new draft:

text
draft
→ CREATE active
→ draft removed

24. Use optimized Activate ​

Declare:

abap
draft action Activate optimized;

The optimized variant can avoid unnecessary repeated determination/validation work when the BO modeling rules allow it.


25. Discard ​

Declare:

abap
draft action Discard;

Discard:

text
deletes the draft instance
keeps the active instance unchanged

For a new draft, Discard means:

text
no active business object is created

26. Resume ​

Declare:

abap
draft action Resume;

Resume is used when work on an existing draft continues after the original exclusive lock period has expired.

It re-establishes the draft editing lock where permitted.


27. Prepare ​

Prepare is a:

text
draft determine action

It runs selected existing:

text
validations
determinations

before activation.

In Fiori Elements, Save invokes Prepare before Activate.


Connect Existing Validations to Prepare ​

28. Why existing on-save validations need Prepare ​

You already have:

text
validateCustomer
validateDate
validateFee

For draft activation, you want those business checks to run while the draft is being prepared for transition to active data.

Add them to:

text
Prepare

29. Define Prepare ​

Use:

abap
draft determine action Prepare
{
  validation validateCustomer;
  validation validateDate;
  validation validateFee;
}

You are reusing the Lesson 13 validations.

You are not creating duplicate validation methods.


30. Why setInitialStatus is not listed in Prepare ​

setInitialStatus is:

text
on modify { create; }

It runs when the new draft is created.

It does not need to be delayed until activation.

Same for:

text
setResponsibleUser

31. Save flow with validation ​

Fiori Elements Save conceptually triggers:

text
Prepare
   ↓
validateCustomer
validateDate
validateFee
   ↓
valid?
 ┌─┴─┐
yes  no
 ↓    ↓
Activate
     draft remains
     messages returned

Invalid draft data should not become active.


Complete Base BDEF Shape ​

32. Base BDEF reference ​

Your base BDEF should now be equivalent to:

abap
managed implementation in class zbp_r_resv_### unique;
strict ( 2 );
with draft;

define behavior for ZR_Reservation_### alias Reservation
persistent table zresv_###
draft table zdresv_###
lock master
total etag LastChangedAt
authorization master ( global, instance )
etag master LocalLastChangedAt
{
  create;
  update;
  delete;

  field ( numbering : managed, readonly ) Uuid;

  field ( readonly )
    Status,
    ResponsibleUser,
    LocalCreatedBy,
    LocalCreatedAt,
    LocalLastChangedBy,
    LocalLastChangedAt,
    LastChangedAt;

  field ( mandatory:create, readonly:update ) ReservationNo;

  field ( features : instance ) Fee, CurrencyCode;

  determination setInitialStatus on modify { create; }
  determination setResponsibleUser on modify { create; }

  validation validateCustomer on save
    { create; field CustomerName; }

  validation validateDate on save
    { create; field ReservationDate; }

  validation validateFee on save
    { create; field Fee, CurrencyCode; }

  action ( features : instance, authorization: update )
    confirm result [1] $self;

  action ( features : instance, authorization: update )
    cancel result [1] $self;

  draft action Edit;
  draft action Activate optimized;
  draft action Discard;
  draft action Resume;

  draft determine action Prepare
  {
    validation validateCustomer;
    validation validateDate;
    validation validateFee;
  }

  mapping for zresv_###
  {
    Uuid               = uuid;
    ReservationNo      = reservation_no;
    CustomerName       = customer_name;
    CustomerEmail      = customer_email;
    WorkshopCode       = workshop_code;
    ReservationDate    = reservation_date;
    Status             = status;
    ResponsibleUser    = responsible_user;
    Fee                = fee;
    CurrencyCode       = currency_code;
    Notes              = notes;
    LocalCreatedBy     = local_created_by;
    LocalCreatedAt     = local_created_at;
    LocalLastChangedBy = local_last_changed_by;
    LocalLastChangedAt = local_last_changed_at;
    LastChangedAt      = last_changed_at;
  }
}

Draft-Aware Authorization ​

33. Why Lesson 15 authorization must be revisited ​

Draft introduces the authorization-controlled action:

text
Edit

It must fit the existing update-style owner policy.

Prepare is a draft determine action, not an independently authorization-controlled action. Its components do not exist in the generated authorization structures, so do not check or populate authorization fields for it.

Do not assume the old Lesson 15 handler automatically knows about newly introduced draft requests.


34. Global authorization — treat Edit like update ​

Your global training policy already allows update.

Apply the same update-style policy to a request for:

text
%action-Edit

receives the same allow decision.

Conceptually:

text
update requested
OR Edit requested
→ update-style authorization

35. Global authorization pattern ​

Use a pattern equivalent to:

abap
METHOD get_global_authorizations.

  IF requested_authorizations-%create = if_abap_behv=>mk-on.
    result-%create = if_abap_behv=>auth-allowed.
  ENDIF.

  IF requested_authorizations-%update = if_abap_behv=>mk-on.
    result-%update = if_abap_behv=>auth-allowed.
  ENDIF.

  IF requested_authorizations-%action-Edit = if_abap_behv=>mk-on.
    result-%action-Edit = if_abap_behv=>auth-allowed.
  ENDIF.

  IF requested_authorizations-%delete = if_abap_behv=>mk-on.
    result-%delete = if_abap_behv=>auth-allowed.
  ENDIF.

ENDMETHOD.

This keeps the existing create/delete handling and fills only requested components. The global authorization result is a structure.


36. Instance authorization — owner rule remains ​

For an existing active Reservation:

text
ResponsibleUser = current user
→ update-style operations allowed

That should also protect:

text
Edit

when RAP requests its authorization result. Normal update/delete authorization continues through %update and %delete.


37. Instance authorization request detection ​

Treat either of these as requiring the same owner check:

text
%update
%action-Edit

Then fill the relevant requested result components with:

text
auth-allowed
or
auth-unauthorized

Unlike global authorization, get_instance_authorizations returns a result table. Append one row per instance with its %tky, then fill the requested components on that row.

Use:

abap
METHOD get_instance_authorizations.

  READ ENTITIES OF ZR_Reservation_### IN LOCAL MODE
    ENTITY Reservation
      FIELDS ( ResponsibleUser )
      WITH CORRESPONDING #( keys )
    RESULT DATA(reservations)
    FAILED failed.

  DATA current_user TYPE abp_creation_user.
  current_user = cl_abap_context_info=>get_user_technical_name( ).

  LOOP AT reservations INTO DATA(reservation).

    APPEND VALUE #(
      %tky = reservation-%tky
    ) TO result ASSIGNING FIELD-SYMBOL(<authorization>).

    IF requested_authorizations-%update = if_abap_behv=>mk-on.

      <authorization>-%update =
        COND #(
          WHEN reservation-ResponsibleUser = current_user
          THEN if_abap_behv=>auth-allowed
          ELSE if_abap_behv=>auth-unauthorized
        ).

    ENDIF.

    IF requested_authorizations-%action-Edit = if_abap_behv=>mk-on.

      <authorization>-%action-Edit =
        COND #(
          WHEN reservation-ResponsibleUser = current_user
          THEN if_abap_behv=>auth-allowed
          ELSE if_abap_behv=>auth-unauthorized
        ).

    ENDIF.

    IF requested_authorizations-%delete = if_abap_behv=>mk-on.
      <authorization>-%delete = if_abap_behv=>auth-allowed.
    ENDIF.

  ENDLOOP.

ENDMETHOD.

The delete decision retains Lesson 15's classroom cleanup policy. Copy the full %tky from the read result so each authorization row retains the instance's active/draft identity.


38. Why Activate is different ​

Activation performs the underlying save:

text
CREATE active
or
UPDATE active

Authorization for the modifying operation protects the transition.

Do not invent a separate custom authorization model for:

text
Activate

in this lesson.


39. Why Discard is different ​

Discard removes:

text
draft data

The draft framework controls that lifecycle action.

It is not a business delete of the active Reservation.


40. New drafts and ownership ​

Your new determination:

text
setResponsibleUser

runs on create.

Therefore a new draft receives:

text
ResponsibleUser = current user

automatically.

This makes the existing owner-based DCL and instance authorization compatible with UI draft creation.


Draft-Enable the Projection ​

41. Open the projection BDEF ​

Open the Lesson 16 projection Behavior Definition for:

text
ZC_RESERVATION_###

Current header:

abap
projection;
strict ( 2 );

Add:

abap
use draft;

42. Why use draft ​

The base BO is now draft-enabled.

The projection decides whether the service should expose that draft behavior.

For this UI service:

text
yes

So declare:

abap
use draft;

43. Reuse draft actions explicitly ​

Strict projection behavior requires the draft actions to be listed.

Add:

abap
use action Edit;
use action Activate;
use action Discard;
use action Resume;
use action Prepare;

44. Complete projection BDEF ​

Use:

abap
projection;
strict ( 2 );
use draft;

define behavior for ZC_Reservation_### alias Reservation
use etag
{
  use create;
  use update;
  use delete;

  use action Edit;
  use action Activate;
  use action Discard;
  use action Resume;
  use action Prepare;

  use action confirm;
  use action cancel;
}

The projection does not repeat:

text
draft table
total etag

Those are reused implementation details from the base BO.


Activate the Draft Stack ​

45. Activation order ​

A practical activation sequence is:

text
1. root CDS / persistence changes
2. draft table
3. base BDEF
4. Behavior Pool
5. projection BDEF
6. service artifacts if ADT reports dependencies

Use:

text
Ctrl+Shift+F3

when related activation is helpful.


46. Service Definition does not change ​

Your Lesson 16 Service Definition already exposes:

text
ZC_RESERVATION_###

The entity name did not change.

No new service entity is required just because the BO became draft-enabled.


47. Service Binding does not need a new name ​

Keep:

text
ZUI_RESV_###_O4

The OData V4 UI binding is already the correct service type.

Activate changed artifacts and refresh/reopen the preview.

If the binding editor indicates publishing is required, publish the local service again.


Runtime Test 1 — New Draft ​

48. Open the Fiori Elements preview ​

Open:

text
ZUI_RESV_###_O4

Launch:

text
Reservations
→ Preview

The UI should now present a draft-aware transactional flow.


49. Start a new Reservation ​

Choose:

text
Create

In an OData V4 draft UI, Create creates:

text
a new draft

not an active row immediately.

Enter valid values such as:

text
ReservationNo   = 99100001
CustomerName    = Draft Student
CustomerEmail   = draft@example.com
WorkshopCode    = RAP401
ReservationDate = today
Fee             = 300.00
CurrencyCode    = EUR
Notes           = New draft test

Do not enter:

text
Status
ResponsibleUser
Uuid
admin fields

The BO owns those values.


50. Observe automatic fields ​

The create determinations should produce:

text
Status = N
ResponsibleUser = current user

The BO remains the source of those defaults.


51. Do not save yet ​

Leave the new object in draft state.

At this point:

text
draft exists
active instance does not yet exist

This is the best moment to inspect persistence.


52. Inspect the active table ​

Open:

text
ZRESV_###

Use:

text
Alt+F8

Filter:

text
99100001

Expected:

text
no active row yet

53. Inspect the draft table ​

Open:

text
ZDRESV_###

Use Table Data Preview.

Find the draft corresponding to:

text
99100001

Expected:

text
draft row exists

Also inspect the generated technical draft administration fields.

Do not modify them.


54. Save the new draft ​

Return to the Fiori preview.

Choose:

text
Save

Conceptually:

text
Prepare
↓
validations
↓
Activate
↓
CREATE active instance
↓
remove draft

55. Verify after activation ​

Active table:

text
ZRESV_###
→ 99100001 exists

Draft table:

text
ZDRESV_###
→ draft for 99100001 removed

Protected projection:

text
ZC_RESERVATION_###
→ active row visible

Runtime Test 2 — Edit Draft and Discard ​

56. Open active 99100001 ​

From the Fiori Elements preview, open the active Reservation.

Choose:

text
Edit

RAP creates an:

text
edit draft

from the active instance.


57. Change Notes only ​

Change:

text
Notes

to:

text
This change will be discarded

Do not save.


58. Inspect active persistence while editing ​

Open:

text
ZRESV_###

Expected:

text
active Notes still contain the old saved value

Editing has not overwritten active persistence.


59. Inspect draft persistence ​

Open:

text
ZDRESV_###

Expected:

text
draft row contains the unsaved Notes change

Now you can see the two versions simultaneously.


60. Discard the edit draft ​

Return to the UI.

Choose the UI operation equivalent to:

text
Cancel / Discard

Expected:

text
draft row removed
active row unchanged

61. Verify discard ​

Active:

text
Notes = original saved value

Draft:

text
no edit draft for 99100001

This proves Discard is not Delete.


Runtime Test 3 — Validation During Draft Save ​

62. Edit the active Reservation again ​

Choose:

text
Edit

Set:

text
ReservationDate = yesterday

This violates the Lesson 13 rule.


63. Attempt Save ​

Choose:

text
Save

The draft lifecycle invokes:

text
Prepare

and therefore:

text
validateDate

Expected:

text
activation fails
validation message appears
draft remains available for correction
active row remains unchanged

64. Why the draft remains ​

The invalid data is allowed to exist as:

text
work in progress

but it is not allowed to become:

text
active business data

This is one of the main benefits of draft.


65. Correct the date ​

Change:

text
ReservationDate

back to:

text
today or future

Choose:

text
Save

Expected:

text
Prepare succeeds
Activate succeeds
active row updated
draft removed

Runtime Test 4 — Resume Concept ​

66. What Resume solves ​

Draft editing can outlive an ordinary database lock.

If the exclusive lock expires while the durable draft still exists:

text
Resume

re-establishes the editing lock when permitted.

You do not need to wait for a real lock timeout during class.

Understand the lifecycle role.


67. Durable draft vs short transaction ​

Normal Lesson 12 buffer:

text
short-lived transactional state

Draft:

text
persisted intermediate state
survives across requests/sessions

This distinction is certification-relevant.


Active vs Draft Identity ​

68. Same business object, two versions ​

For an edit draft:

text
active version
+
draft version

refer to the same logical BO instance.

The draft runtime tracks the relationship.

Do not design a second business key for the draft.


69. Managed UUID still matters ​

The same UUID-based identity model continues to support the BO.

Draft does not mean:

text
generate unrelated UUID for active copy

The runtime manages active/draft identity correctly.


Draft Actions vs Business Actions ​

70. Framework draft actions ​

text
Edit
Activate
Discard
Resume
Prepare

manage editing lifecycle.


71. Business actions ​

text
confirm
cancel

express Reservation business transitions.

These remain separate concepts.

Do not rename:

text
confirm

to:

text
Activate

They solve unrelated problems.


72. Example ​

A Reservation can be:

text
active
Status = N

Then:

text
Edit
→ create draft for editing

Later:

text
Activate
→ save draft changes

Then business action:

text
confirm
→ Status N → C

Draft lifecycle and business lifecycle are independent.


Total ETag and Concurrency ​

73. Outdated draft scenario ​

Imagine:

text
User starts edit draft

Then somehow the active instance changes independently.

When the user later tries to continue/activate the old draft:

text
total ETag comparison

helps RAP detect that the draft is based on stale active data.


74. Why LastChangedAt is appropriate ​

The total ETag needs an active timestamp that changes whenever active data changes.

Your existing:

text
LastChangedAt

has the semantic role required for this purpose.


Authorization with Draft ​

75. DCL remains read protection ​

The existing DCL still protects the service's read surface.

Draft does not remove:

text
ResponsibleUser = current user

read authorization.


76. Instance authorization remains write protection ​

Owner-based authorization still protects changes to active business objects and the edit lifecycle.

The authorization handler checks %action-Edit when requested, alongside %update and %delete. Prepare remains part of validation/determination processing and has no independent authorization component.


77. New-draft create authorization ​

Creating a new draft uses the create authorization path.

Our Trial global create policy allows it.

The new determination then assigns:

text
ResponsibleUser = current user

78. Edit-draft authorization ​

Editing an existing active instance must respect the existing owner policy.

That is why:

text
Edit

is handled like update in the authorization implementation.


Common Mistakes ​

79. Mistake — use Status D as Draft ​

Wrong:

text
Status D means RAP draft

Correct:

text
business Status
and
RAP draft state
are separate

80. Mistake — manually create the draft table ​

Prefer:

text
Ctrl+1
Generate draft table

The generated table requires RAP draft administration structure.

Do not guess it manually.


81. Mistake — forget total ETag ​

A draft-enabled BO requires a total ETag on the lock master.

For this BO:

text
LastChangedAt

is the intended field.


82. Mistake — replace local ETag with total ETag ​

Keep both:

text
etag master LocalLastChangedAt
total etag LastChangedAt

They serve different concurrency purposes.


83. Mistake — declare draft actions but no Prepare validations ​

If Prepare contains no relevant validations, the draft UI may reach activation without the intended pre-activation validation flow.

Reuse your existing business validations.


84. Mistake — duplicate validation implementations ​

Do not write:

text
validateCustomerForDraft

when the same rule already exists.

Assign:

text
validateCustomer

to Prepare.


85. Mistake — forget use draft in projection ​

Base draft capability does not automatically mean every projection exposes draft behavior.

Add:

abap
use draft;

to the projection BDEF.


86. Mistake — omit draft actions from strict projection BDEF ​

With strict projection behavior, explicitly reuse:

text
Edit
Activate
Discard
Resume
Prepare

87. Mistake — create a second Service Binding ​

The existing:

text
OData V4 UI

binding is already the right consumption layer.

Draft-enable the BO/projection rather than creating a duplicate service merely for draft.


88. Mistake — use direct SQL on draft table ​

Never use normal business logic to:

text
INSERT draft row
UPDATE draft row
DELETE draft row

RAP owns draft persistence.


89. Mistake — authorization ignores draft actions ​

After enabling Draft, revisit:

text
get_global_authorizations
get_instance_authorizations

Handle the generated %action-Edit component using the update-style policy. Do not add authorization components for the draft determine action Prepare.

Keep the result shapes distinct: global authorization fills a structure; instance authorization appends table rows keyed by %tky.


90. Mistake — let the user type owner identity ​

Lesson 17 hardens:

text
ResponsibleUser

as system-derived.

New draft creation should not depend on typing a technical user ID.


Certification Alignment ​

91. Practical draft tasks ​

A system-based RAP task can ask you to:

text
add with draft
define a draft table
generate draft persistence
add total etag
declare draft actions
wire validations into Prepare
draft-enable a projection
repair missing use action statements
test Fiori draft behavior

You should recognize which artifact owns each part.


92. Draft repair map ​

If:

text
draft table missing
→ base BDEF + Quick Fix

outdated draft/concurrency error
→ total ETag / timestamp model

Save allows invalid data
→ Prepare assignments / validation

UI has no Edit/Save draft flow
→ base draft + projection use draft + service metadata

Edit unauthorized unexpectedly
→ authorization handler draft requests

active data changes before Save
→ draft architecture is wrong / bypassed

Discard deletes active row
→ severe modeling/runtime misunderstanding

Knowledge Check ​

93. Questions ​

1. Why does RAP Draft need separate persistence? ​

2. What is the difference between a new draft and an edit draft? ​

3. Why is Status N not the same as Draft? ​

4. What does with draft do? ​

5. Why should ADT generate the draft table? ​

6. What is the difference between local ETag and total ETag? ​

7. Why is total ETag mandatory for draft? ​

8. What does Edit do? ​

9. What does Activate do? ​

10. What does Discard do? ​

11. What does Resume do? ​

12. What does Prepare do? ​

13. Why are Lesson 13 validations assigned to Prepare? ​

14. Why does ResponsibleUser become system-derived? ​

15. Why must authorization handlers be revisited after draft enablement? ​

16. What does use draft do in the projection BDEF? ​

17. Why are draft actions listed explicitly in strict projection behavior? ​

18. Does the Service Definition need a second Reservation entity for draft? ​

19. Does an unsaved edit draft overwrite active persistence? ​

20. What happens to the draft row after successful activation? ​


Teacher-Led Completion Checklist ​

94. Checklist ​


End-of-Day Mental Model ​

95. Final model ​

text
             Fiori Elements
                   ↓
              OData V4
                   ↓
          Draft-enabled Projection
                   ↓
          Draft-enabled RAP BO
                   ↓
        ┌──────────┴──────────┐
        ↓                     ↓
  Active Persistence     Draft Persistence
     ZRESV_###             ZDRESV_###
        ↑                     │
        └──── Activate ───────┘

Draft lifecycle:

text
Active
  ↓ Edit
Edit Draft
  ├─ Discard → Active unchanged
  └─ Prepare → Validate
                 ↓
              Activate
                 ↓
          Active updated

New-object lifecycle:

text
Create
  ↓
New Draft
  ├─ Discard → nothing active
  └─ Prepare → Validate
                 ↓
              Activate
                 ↓
          Active created

Lesson 18 will extend this from a single-node BO to:

text
Compositions
→ parent/child business objects
→ draft-aware composition trees