Skip to content

Lesson 12 — EML and the RAP Transactional Buffer ​

Quick reference

Keep the EML Cheat Sheet nearby for command syntax, RAP responses, and transaction handling.

In Lesson 10, you built the Business Object structure:

text
ZRESV_###
    ↓
ZR_RESERVATION_###

In Lesson 11, you added managed transactional behavior:

text
ZR_RESERVATION_###
    ↓
Managed Behavior Definition
    ↓
ZBP_R_RESV_###

But so far, nobody has actually used that behavior.

Today that changes.

You will write an ABAP consumer that talks to the Reservation Business Object through:

text
EML

instead of modifying:

text
ZRESV_###

directly.

The architecture becomes:

text
ZCL_RESV_EML_###
        ↓
       EML
        ↓
ZR_RESERVATION_###
        ↓
Managed RAP Behavior
        ↓
ZRESV_###

Today is where managed RAP becomes visible at runtime.


Lesson information ​

Teacher-led timeAbout 3 hours
Self-practice timeAbout 3 hours
EnvironmentSAP BTP ABAP Trial
PrerequisiteLesson 11
Business ObjectZR_RESERVATION_###
Consumer classZCL_RESV_EML_###
Main outcomeConsume a RAP BO with EML
Runtime focusTransactional buffer + save boundary

Replace:

text
###

with your own student/group suffix.


Learning objectives ​

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

  • explain what Entity Manipulation Language is;
  • explain why EML is used instead of direct SQL for RAP BO consumption;
  • distinguish the RAP Business Object from its persistence table;
  • use MODIFY ENTITIES to create, update, and delete BO instances;
  • use %cid as a temporary create identifier;
  • interpret MAPPED, FAILED, and REPORTED;
  • observe managed UUID numbering through MAPPED;
  • use READ ENTITIES to read BO instances;
  • explain the RAP transactional buffer;
  • prove that an uncommitted modification is visible inside the same RAP transaction;
  • use COMMIT ENTITIES to trigger the RAP save sequence;
  • use ROLLBACK ENTITIES to discard buffered changes;
  • distinguish interaction-phase responses from save-phase responses;
  • verify committed state with EML and CDS Data Preview;
  • explain why COMMIT WORK is not the teaching focus for RAP consumers;
  • explain why IN LOCAL MODE is not used in this external consumer class.

1. What is EML? ​

EML stands for:

text
Entity Manipulation Language

It is the ABAP language syntax used to work with RAP Business Objects.

With EML, ABAP code can request operations such as:

text
READ
CREATE
UPDATE
DELETE
EXECUTE ACTION

against the Business Object contract.

For example:

text
ABAP consumer
     ↓
READ ENTITIES / MODIFY ENTITIES
     ↓
RAP Business Object

2. Why not just use ABAP SQL? ​

You already know how to write:

abap
INSERT zresv_### ...
UPDATE zresv_### ...
DELETE FROM zresv_### ...

Those statements modify persistence directly.

Once the Reservation is owned by a RAP Business Object, normal application consumers should work through:

text
RAP behavior

because direct table writes can bypass current or future behavior such as:

text
validations
determinations
authorization
actions
feature control
messages
locking expectations
transactional buffering
save sequencing

The key transition is:

text
Before RAP
ABAP code → ABAP SQL → table

With RAP
ABAP code → EML → RAP BO → persistence

3. EML does not mean OData ​

EML is an ABAP consumption mechanism.

It does not require:

text
Service Definition
Service Binding
OData
Fiori Elements

Today the consumer is another ABAP class in the same ABAP system.

Later an OData consumer can reach the same Business Object through a business service.


4. The RAP transaction ​

A RAP transaction moves BO data from one consistent state to another.

A simplified model is:

text
EML request
    ↓
interaction phase
    ↓
RAP transactional buffer
    ↓
COMMIT ENTITIES
    ↓
save sequence
    ↓
persistence

The important new concept is:

text
transactional buffer

5. What is the transactional buffer? ​

When an EML consumer creates or changes a BO instance, the change participates in the RAP transaction.

Do not imagine every EML modification as:

text
one immediate SQL statement

Instead, think:

text
requested BO change
      ↓
transactional buffer
      ↓
later save boundary

This lets multiple BO operations belong to one logical transaction.


6. What ends the RAP transaction? ​

In an external EML test/consumer scenario, the important statements are:

text
COMMIT ENTITIES
ROLLBACK ENTITIES

COMMIT ENTITIES ​

Triggers the RAP save sequence for all BOs changed in the current transaction. A successful save persists the buffered work together. If an on-save validation fails, the transaction is not partially committed.

ROLLBACK ENTITIES ​

Discards the current RAP transactional changes and resets the transactional buffer.


7. Why not teach COMMIT WORK here? ​

RAP integrates with the ABAP LUW, and COMMIT WORK can implicitly trigger RAP saving.

However, this course teaches the RAP-specific transaction boundary explicitly:

abap
COMMIT ENTITIES

That makes the BO save sequence visible and lets the consumer retrieve RAP save responses.

For RAP learning and certification work, this is the clearer model.


8. The class we will create ​

Create:

text
ZCL_RESV_EML_###

Implement:

text
IF_OO_ADT_CLASSRUN

Architecture:

text
ZCL_RESV_EML_###
        ↓
       EML
        ↓
Reservation BO

This class is a BO consumer.

It is not a Behavior Pool.


9. Create the consumer class ​

Right-click your package.

Choose:

text
New
  → ABAP Class

Use:

text
Name:        ZCL_RESV_EML_###
Description: Reservation EML Consumer

Add:

abap
INTERFACES if_oo_adt_classrun.

Activate the empty class before continuing.


10. The lifecycle we will prove ​

The class will demonstrate:

text
CREATE two Reservations
        ↓
READ before COMMIT
        ↓
COMMIT
        ↓
READ persisted state
        ↓
UPDATE one Reservation
        ↓
READ changed buffer state
        ↓
ROLLBACK
        ↓
prove old value remains
        ↓
UPDATE again
        ↓
COMMIT
        ↓
DELETE second Reservation
        ↓
COMMIT
        ↓
final READ + F8 preview

This gives you a complete RAP consumer lifecycle.


11. Why create two Reservations? ​

We want the final state to be visible after the class finishes.

So the demonstration uses:

text
Reservation A
→ survives
→ gets updated

Reservation B
→ gets deleted through EML

After the final run, CDS Data Preview should show Reservation A but not Reservation B.


12. Use two reserved training numbers ​

Use:

text
92000001
92000002

These values belong only to this Lesson 12 demonstration.

The Companion's repeatable cleanup pattern lets you rerun the class several times.

During the normal first guided run, create them only once.


13. First MODIFY ENTITIES ​

Start with a create request:

abap
MODIFY ENTITIES OF ZR_Reservation_###
  ENTITY Reservation
    CREATE FIELDS (
      ReservationNo
      CustomerName
      CustomerEmail
      WorkshopCode
      ReservationDate
      Status
      Fee
      CurrencyCode
      Notes )
    WITH VALUE #(
      ( %cid            = 'RES_A'
        ReservationNo   = '92000001'
        CustomerName    = 'EML Student A'
        CustomerEmail   = 'student.a@example.com'
        WorkshopCode    = 'RAP101'
        ReservationDate = cl_abap_context_info=>get_system_date( )
        Status           = 'N'
        Fee              = '150.00'
        CurrencyCode     = 'EUR'
        Notes            = 'Created with EML' )

      ( %cid            = 'RES_B'
        ReservationNo   = '92000002'
        CustomerName    = 'EML Student B'
        CustomerEmail   = 'student.b@example.com'
        WorkshopCode    = 'RAP101'
        ReservationDate = cl_abap_context_info=>get_system_date( )
        Status           = 'N'
        Fee              = '175.00'
        CurrencyCode     = 'EUR'
        Notes            = 'Delete demonstration' ) )
  MAPPED DATA(mapped_create)
  FAILED DATA(failed_create)
  REPORTED DATA(reported_create).

Replace ###.


14. Why is Uuid missing from CREATE FIELDS? ​

Lesson 11 declared:

abap
field ( numbering : managed, readonly ) Uuid;

Therefore the consumer does not provide the UUID.

RAP generates it.

This is managed early numbering.


15. What is %cid? ​

The create request uses:

text
%cid

Think of %cid as:

text
consumer-side temporary identifier

Before the consumer knows the new technical key, it can refer to the requested create instance using %cid.

Example:

text
RES_A

is not stored as the Reservation UUID.

It is only the create request's correlation identifier.


16. Inspect MAPPED ​

The create request returns:

text
MAPPED

For managed early numbering, RAP can return the generated key immediately.

Conceptually:

text
%cid = RES_A
      ↓
RAP generates UUID
      ↓
MAPPED connects RES_A to that UUID

Output:

abap
out->write( mapped_create ).

Look for:

text
RES_A
RES_B
generated UUIDs

17. Extract the generated UUIDs ​

After a successful create request:

abap
IF failed_create IS NOT INITIAL
   OR NOT line_exists( mapped_create-reservation[ %cid = 'RES_A' ] )
   OR NOT line_exists( mapped_create-reservation[ %cid = 'RES_B' ] ).
  out->write( failed_create ).
  out->write( reported_create ).
  ROLLBACK ENTITIES.
  RETURN.
ENDIF.

DATA(uuid_a) = mapped_create-reservation[ %cid = 'RES_A' ]-Uuid.
DATA(uuid_b) = mapped_create-reservation[ %cid = 'RES_B' ]-Uuid.

Use %cid to correlate each response with its create request; the response table order is not the business identity.

The complete Companion consumer applies this guard throughout the lifecycle.

For the guided exercise, first inspect mapped_create so you understand its shape.


18. Inspect FAILED ​

The create request also returns:

text
FAILED

FAILED identifies entity instances for which the requested operation failed.

Output:

abap
out->write( failed_create ).

For today's valid creates, expect it to be empty.

Later validations and authorization can cause meaningful failures.


19. Inspect REPORTED ​

The third response is:

text
REPORTED

It carries RAP-reported information/messages associated with BO processing.

Output:

abap
out->write( reported_create ).

Today it will normally be empty because you have not implemented business messages yet.

Lesson 13 will make REPORTED much more interesting.


20. Stop if CREATE failed ​

Do not continue blindly if the create operation failed.

Use a guard such as:

abap
IF failed_create IS NOT INITIAL.
  out->write( 'Create failed. Stop the lifecycle.' ).
  ROLLBACK ENTITIES.
  RETURN.
ENDIF.

This protects the later steps from assuming that mapped keys exist.


21. Read the new instance before commit ​

Now use EML to read Reservation A before COMMIT ENTITIES:

abap
READ ENTITIES OF ZR_Reservation_###
  ENTITY Reservation
    FIELDS (
      Uuid
      ReservationNo
      CustomerName
      Status
      Fee
      CurrencyCode
      Notes )
    WITH VALUE #( ( Uuid = uuid_a ) )
  RESULT DATA(buffer_read)
  FAILED DATA(failed_buffer_read).

Output:

abap
out->write( buffer_read ).

22. What does the pre-commit READ prove? ​

The instance can already be read inside the same RAP transaction.

That demonstrates:

text
CREATE request
      ↓
transactional buffer
      ↓
READ sees buffered state

The point is not that the table was already permanently saved.

The point is that the RAP transaction has a working state before persistence.


23. Commit the two creates ​

Now persist the buffered work:

abap
COMMIT ENTITIES
  RESPONSE OF ZR_Reservation_###
    FAILED DATA(failed_commit_create)
    REPORTED DATA(reported_commit_create).
DATA(create_commit_subrc) = sy-subrc.

Then inspect:

abap
out->write( failed_commit_create ).
out->write( reported_commit_create ).

For today's simple BO, expect a successful commit.


24. Why can COMMIT have its own responses? ​

The interaction request and the save sequence are not the same phase.

You already inspected responses from:

text
MODIFY ENTITIES

Now the long form of:

text
COMMIT ENTITIES RESPONSE OF ...

can return save-phase:

text
FAILED
REPORTED

This distinction becomes essential when Lesson 13 introduces validations during save processing.


25. Check sy-subrc after COMMIT ​

Capture sy-subrc immediately after:

abap
COMMIT ENTITIES

as shown above, before output or further operations. Check the captured value:

abap
IF create_commit_subrc = 0 AND failed_commit_create IS INITIAL.
  out->write( 'Create commit succeeded.' ).
ELSE.
  out->write( 'Create commit failed.' ).
  ROLLBACK ENTITIES.
  RETURN.
ENDIF.

An on-save validation failure produces sy-subrc = 4; Lesson 13 demonstrates this. Stop and roll back after a failed save in these consumer exercises.

Do not use sy-dbcnt as the RAP commit success indicator.


26. Read after commit ​

Read Reservation A again:

abap
READ ENTITIES OF ZR_Reservation_###
  ENTITY Reservation
    ALL FIELDS
    WITH VALUE #( ( Uuid = uuid_a ) )
  RESULT DATA(after_create_commit)
  FAILED DATA(failed_after_create_commit).

Output the result.

Now inspect administrative fields such as:

text
LocalCreatedBy
LocalCreatedAt
LocalLastChangedBy
LocalLastChangedAt
LastChangedAt

You are now seeing the managed BO state after persistence.


27. First UPDATE — do not commit it ​

Change Reservation A from:

text
N

to:

text
C

using EML:

abap
MODIFY ENTITIES OF ZR_Reservation_###
  ENTITY Reservation
    UPDATE FIELDS ( Status Notes )
    WITH VALUE #(
      ( Uuid   = uuid_a
        Status = 'C'
        Notes  = 'Buffered change - will rollback' ) )
  FAILED DATA(failed_update_rollback)
  REPORTED DATA(reported_update_rollback).

IF failed_update_rollback IS NOT INITIAL.
  out->write( failed_update_rollback ).
  out->write( reported_update_rollback ).
  ROLLBACK ENTITIES.
  RETURN.
ENDIF.

Do not commit yet.


28. Read the changed buffer state ​

Immediately read Reservation A:

abap
READ ENTITIES OF ZR_Reservation_###
  ENTITY Reservation
    FIELDS ( Uuid ReservationNo Status Notes )
    WITH VALUE #( ( Uuid = uuid_a ) )
  RESULT DATA(before_rollback)
  FAILED DATA(failed_before_rollback).

Expected inside the transaction:

text
Status = C
Notes  = Buffered change - will rollback

29. Roll back the UPDATE ​

Now execute:

abap
ROLLBACK ENTITIES.

This discards the current RAP transactional changes since the last commit and resets the buffer.


30. Read after rollback ​

Read Reservation A again:

abap
READ ENTITIES OF ZR_Reservation_###
  ENTITY Reservation
    FIELDS ( Uuid ReservationNo Status Notes )
    WITH VALUE #( ( Uuid = uuid_a ) )
  RESULT DATA(after_rollback)
  FAILED DATA(failed_after_rollback).

Expected:

text
Status = N
Notes  = Created with EML

This is one of the most important observations in the lesson.


31. What rollback proved ​

You observed:

text
Persistent state = N

EML UPDATE
    ↓
Buffer state = C

ROLLBACK ENTITIES
    ↓
Buffer discarded
    ↓
Persistent state still = N

That is the RAP transactional buffer in action.


32. UPDATE again and keep it ​

Perform the update again, this time with a note that should persist:

abap
MODIFY ENTITIES OF ZR_Reservation_###
  ENTITY Reservation
    UPDATE FIELDS ( Status Notes )
    WITH VALUE #(
      ( Uuid   = uuid_a
        Status = 'C'
        Notes  = 'Confirmed through EML' ) )
  FAILED DATA(failed_update_commit)
  REPORTED DATA(reported_update_commit).

IF failed_update_commit IS NOT INITIAL.
  out->write( failed_update_commit ).
  out->write( reported_update_commit ).
  ROLLBACK ENTITIES.
  RETURN.
ENDIF.

If the update succeeds, commit it:

abap
COMMIT ENTITIES
  RESPONSE OF ZR_Reservation_###
    FAILED DATA(failed_commit_update)
    REPORTED DATA(reported_commit_update).
DATA(update_commit_subrc) = sy-subrc.

IF update_commit_subrc <> 0 OR failed_commit_update IS NOT INITIAL.
  out->write( failed_commit_update ).
  out->write( reported_commit_update ).
  ROLLBACK ENTITIES.
  RETURN.
ENDIF.

33. Verify the committed UPDATE ​

Read Reservation A again.

Expected:

text
ReservationNo = 92000001
Status        = C
Notes         = Confirmed through EML

Also compare:

text
LocalCreatedAt
LocalLastChangedAt

The last-change information should reflect the managed lifecycle.


34. DELETE Reservation B through EML ​

Now delete only Reservation B:

abap
MODIFY ENTITIES OF ZR_Reservation_###
  ENTITY Reservation
    DELETE FROM VALUE #( ( Uuid = uuid_b ) )
  FAILED DATA(failed_delete)
  REPORTED DATA(reported_delete).

IF failed_delete IS NOT INITIAL.
  out->write( failed_delete ).
  out->write( reported_delete ).
  ROLLBACK ENTITIES.
  RETURN.
ENDIF.

Do not use:

abap
DELETE FROM zresv_###

The delete request goes through the BO contract.


35. Commit the DELETE ​

Persist the delete:

abap
COMMIT ENTITIES
  RESPONSE OF ZR_Reservation_###
    FAILED DATA(failed_commit_delete)
    REPORTED DATA(reported_commit_delete).
DATA(delete_commit_subrc) = sy-subrc.

IF delete_commit_subrc <> 0 OR failed_commit_delete IS NOT INITIAL.
  out->write( failed_commit_delete ).
  out->write( reported_commit_delete ).
  ROLLBACK ENTITIES.
  RETURN.
ENDIF.

Check:

text
FAILED
REPORTED
sy-subrc

36. Prove Reservation B is gone ​

Try to read it through EML:

abap
READ ENTITIES OF ZR_Reservation_###
  ENTITY Reservation
    FIELDS ( Uuid ReservationNo Status )
    WITH VALUE #( ( Uuid = uuid_b ) )
  RESULT DATA(deleted_read)
  FAILED DATA(failed_deleted_read).

The result should contain no successful Reservation B instance.

Inspect the failed read response as part of the exercise.


37. Final read of Reservation A ​

Read the surviving Reservation A:

abap
READ ENTITIES OF ZR_Reservation_###
  ENTITY Reservation
    ALL FIELDS
    WITH VALUE #( ( Uuid = uuid_a ) )
  RESULT DATA(final_read)
  FAILED DATA(failed_final_read).

Output it.

Expected business state:

text
ReservationNo = 92000001
Status        = C
Notes         = Confirmed through EML

38. Run the class ​

Activate:

text
Ctrl+F3

Run:

text
F9

Your output should demonstrate these phases:

text
CREATE responses
pre-commit READ
create COMMIT responses
post-commit READ
buffered UPDATE
ROLLBACK proof
committed UPDATE
DELETE responses
final READ

Do not focus only on the final row.

The important learning is the state transition through the RAP transaction.


39. Preview the final state with F8 ​

After the class finishes, open:

text
ZR_RESERVATION_###

Press:

text
F8

Filter or find:

text
ReservationNo = 92000001

Expected:

text
92000001 exists
Status = C

Then check:

text
92000002

Expected:

text
not present

This is the visible payoff of the lesson.


40. Compare EML output with Data Preview ​

The class output shows the RAP interaction and transaction responses.

CDS Data Preview shows the final persisted state.

Use both views:

text
F9 class output
=
what happened during the RAP transaction

F8 CDS Data Preview
=
what remains persisted afterward

41. MAPPED, FAILED, REPORTED summary ​

MAPPED ​

Most important for operations where preliminary identifiers must be connected to final identifiers.

Today:

text
%cid → managed UUID

FAILED ​

Identifies requested entity operations that failed.

REPORTED ​

Carries reported RAP information/messages.

Today it is mostly quiet.

Lesson 13 will deliberately produce business messages.


42. Why MAPPED matters for managed numbering ​

Before CREATE:

text
consumer knows %cid

After managed early numbering:

text
RAP knows UUID

MAPPED connects them.

This lets the consumer continue working with the newly created instance inside the same logical flow.


43. Interaction-phase vs save-phase responses ​

Do not merge these mentally.

Interaction phase ​

Examples:

text
MODIFY ENTITIES
READ ENTITIES

return operation responses such as:

text
FAILED
REPORTED

MODIFY ENTITIES can additionally return MAPPED for creates with generated identifiers. READ ENTITIES returns the data in RESULT, not MAPPED.

Save phase ​

text
COMMIT ENTITIES RESPONSE OF ...

can return save-related:

text
FAILED
REPORTED

Lesson 13 will make the save-phase distinction important through validations.


44. Why no IN LOCAL MODE? ​

You may see RAP implementation examples containing:

abap
IN LOCAL MODE

Do not add it to today's external consumer class.

IN LOCAL MODE is available when a Behavior Pool accesses its own BO. It bypasses checks such as authorization and feature control for that local access. It cannot be added to an external consumer or to access another BO merely because the caller is a Behavior Pool.

Today's class is acting as a normal external ABAP consumer of the BO.

It should respect the contract.


45. EML is statically checked against the BO ​

One advantage of EML is that your ABAP code is checked against the RAP Business Object definition.

If you try to:

text
use a field that does not exist
request behavior that is not enabled
write a protected field in an invalid way
use the wrong entity name

ADT can detect many problems during syntax checking.

Use:

text
Ctrl+F2

often.


46. Useful ADT navigation ​

From your EML class, place the cursor on:

text
ZR_RESERVATION_###

Use:

text
F3

or:

text
Ctrl+click

where supported.

Move between:

text
consumer class
root CDS
Behavior Definition
Behavior Pool
persistence table

Certification work is faster when you can navigate the model quickly.


47. What EML does not replace ​

EML is how ABAP works with RAP BOs.

It does not replace:

text
CDS modeling
Behavior Definitions
business services
OData
Fiori Elements

Instead, it is one consumer path.

Architecture:

text
ABAP consumer → EML ┐
                    │
OData consumer ─────┼→ RAP Business Object
                    │
future UI ──────────┘

48. Do not use direct persistence writes as a shortcut ​

After creating the EML class, do not mix in:

abap
UPDATE zresv_###
DELETE FROM zresv_###

just because those statements are familiar.

The point of this lesson is to observe the BO contract and transaction.

A read-only SQL query used only for controlled training setup is different from bypassing RAP for writes.

All business modifications in this lesson must go through EML.


49. Repeatability note ​

If you rerun the guided class, the reserved business numbers may already exist from an earlier run.

The Companion's repeatable reset pattern:

text
reads existing training UUIDs
      ↓
deletes them through EML
      ↓
commits the cleanup

Do not solve repeatability with direct table DELETE.


50. Knowledge check ​

1. What does EML stand for? ​

2. Why should a RAP consumer use EML instead of direct table writes? ​

3. What is %cid? ​

4. What does MAPPED tell a consumer? ​

5. What does FAILED contain? ​

6. What is REPORTED for? ​

7. When is the managed UUID available in this scenario? ​

8. What is the RAP transactional buffer? ​

9. Why can READ ENTITIES see a buffered change before commit? ​

10. What does COMMIT ENTITIES trigger? ​

11. What does ROLLBACK ENTITIES do? ​

12. What did the rollback experiment prove? ​

13. Why can COMMIT have separate FAILED and REPORTED responses? ​

14. Why is sy-dbcnt not the main RAP save result? ​

15. Why is IN LOCAL MODE not used in this consumer class? ​

16. How can you visually verify the final persistent state after running the class? ​


51. Teacher-led completion checklist ​


52. End-of-day mental model ​

You can now draw the first complete executable RAP path in the course:

text
ZCL_RESV_EML_###
        ↓
READ / MODIFY ENTITIES
        ↓
RAP transactional buffer
        ↓
COMMIT ENTITIES
        ↓
Managed RAP save sequence
        ↓
ZRESV_###

The progression so far is:

text
Lesson 10
What does the BO look like?

Lesson 11
What can the BO do?

Lesson 12
How does ABAP consume it and control the transaction?

Next, the BO needs real business rules.

Lesson 13 introduces:

text
validations
determinations
RAP messages