EML
RAP / CDS / ODataadvanced

EML Part 4: Cross-BO Calls, COMMIT ENTITIES and ROLLBACK ENTITIES

Key takeaway

Call other business objects safely with EML: changing a second BO from inside your BO, orchestrating several BOs from a program, where COMMIT ENTITIES and ROLLBACK ENTITIES belong, and what happens when one of them fails.

Explanation

📌 KEY POINTS
✅ Several BOs changed via EML are saved together or not at all.

✅ Programs: one COMMIT ENTITIES RESPONSES per logical unit.

✅ ROLLBACK ENTITIES after a failed commit.

⚠️ COMMIT WORK is wrong for RAP changes.

▶ WHERE WE ARE
Parts 1–3 worked with one BO. Real processes span several: approving a purchase request creates a budget reservation; a migration program creates requests and attachments. This part explains how several BOs share one transaction.

━━━━━━━━━━━━━━━━━━━━
▶ 1. ONE LUW, SEVERAL BUSINESS OBJECTS

All BOs changed via EML in the same session share one transactional context. When COMMIT ENTITIES is called (or the framework commits after an OData request), RAP runs the save sequence for every BO that has changes: first finalize and check_before_save for all of them, and only if all pass, save for all. So either both the purchase request and the reservation are saved, or neither.

━━━━━━━━━━━━━━━━━━━━
▶ 2. CALLING ANOTHER BO FROM INSIDE YOUR BO

Allowed in the interaction phase (actions, determinations):

  • MODIFY ENTITIES OF zr_otherbo … without IN LOCAL MODE — the other BO checks authorization and feature control for the current user (EML Part 3).
  • Map the other BO's FAILED/REPORTED into your own failed/reported so the user sees why.
  • Do not call COMMIT ENTITIES — the framework commits both BOs at the end.

Not allowed:

  • MODIFY on any BO during the save phase (finalize, check_before_save, save). Save-phase code may read, but changes must happen before.
  • Changing the other BO's tables directly.

Prefer released interface BOs (…TP) of other teams or SAP over their internal base BOs (Behavior Definitions Part 5).

━━━━━━━━━━━━━━━━━━━━
▶ 3. ORCHESTRATING SEVERAL BOS FROM A PROGRAM

In a report, job or console class you control the transaction:

  1. MODIFY ENTITIES on BO A, then on BO B (using keys from A's MAPPED).
  2. COMMIT ENTITIES RESPONSES OF … to get the save results of both.
  3. If anything failed: ROLLBACK ENTITIES and log.

One COMMIT ENTITIES per logical unit — e.g. one request with its reservation — not one for the whole file, so a single bad record does not block thousands of good ones.

━━━━━━━━━━━━━━━━━━━━
▶ 4. COMMIT ENTITIES VS COMMIT WORK

  • COMMIT ENTITIES triggers the RAP save sequence (with validations) and then the database commit.
  • COMMIT WORK alone does not run the RAP save sequence properly for buffered BO changes; do not use it for RAP changes. Inside behavior implementations neither is allowed.
  • COMMIT ENTITIES IN SIMULATION MODE (available on current releases) runs the save sequence checks without persisting — useful to validate data before a real run.

━━━━━━━━━━━━━━━━━━━━
▶ 5. ROLLBACK ENTITIES

Discards all buffered changes of all BOs in the current transaction. Use it after a failed commit in programs and in test teardown. Inside behavior implementations it is not allowed.

━━━━━━━━━━━━━━━━━━━━
▶ 6. LATE NUMBERING ACROSS BOS

If BO A uses late numbering, its final key exists only after the save. To pass it to BO B in the same transaction, use %pid-based references where BO B supports them, or link the two in the save phase of A (e.g. via additional save) — or split into two transactions with a clear recovery strategy.

━━━━━━━━━━━━━━━━━━━━
▶ STEP BY STEP

  1. From the approve action, create a budget reservation in a second BO and map its messages (code example).
  2. Write a program that creates a request and a reservation per input row, commits per row, and rolls back failed rows.
  3. Test: make the reservation fail — the request must not be saved either.

━━━━━━━━━━━━━━━━━━━━
▶ WHAT YOU HAVE AFTER PART 4

Multi-BO processes that stay consistent. Part 5 covers testing and consistency checks with EML.

Code example

ABAP Code
" ===== Inside PurchaseRequest~approve: change a second BO =====MODIFY ENTITIES OF zr_budgetreservation                 " NOT in local mode: its checks apply  ENTITY Reservation    CREATE FIELDS ( SourceRequestUUID Amount Currency )    WITH VALUE #( FOR r IN requests                  ( %cid = |RES{ sy-tabix }|                    SourceRequestUUID = r-RequestUUID                    Amount            = r-TotalAmount                    Currency          = r-CurrencyCode ) )  FAILED DATA(res_failed)  REPORTED DATA(res_reported). " Forward problems of the other BO to the user of this actionLOOP AT res_reported-reservation INTO DATA(rr).  APPEND VALUE #( %tky = requests[ 1 ]-%tky  %msg = rr-%msg ) TO reported-purchaserequest.ENDLOOP." no COMMIT here - the framework saves BOTH BOs together, or neither " ===== Program: one logical unit per input row =====LOOP AT input_rows INTO DATA(row).   MODIFY ENTITIES OF zr_purchreq    ENTITY PurchaseRequest      CREATE FIELDS ( Description CurrencyCode )      WITH VALUE #( ( %cid = 'R' Description = row-text CurrencyCode = row-currency ) )    MAPPED DATA(req_mapped)    FAILED DATA(req_failed).   IF req_failed IS INITIAL.    MODIFY ENTITIES OF zr_budgetreservation      ENTITY Reservation        CREATE FIELDS ( SourceRequestUUID Amount Currency )        WITH VALUE #( ( %cid = 'B'                        SourceRequestUUID = req_mapped-purchaserequest[ 1 ]-RequestUUID                        Amount = row-amount Currency = row-currency ) )      FAILED DATA(res_failed_row).  ENDIF.   COMMIT ENTITIES    RESPONSES OF zr_purchreq           FAILED DATA(f1) REPORTED DATA(r1)              OF zr_budgetreservation  FAILED DATA(f2) REPORTED DATA(r2).   IF req_failed IS NOT INITIAL OR res_failed_row IS NOT INITIAL     OR f1 IS NOT INITIAL OR f2 IS NOT INITIAL.    ROLLBACK ENTITIES.                  " discard whatever is left in the buffer    " log row as failed with messages from r1 / r2  ENDIF.ENDLOOP. " ===== Never =====" COMMIT WORK.                          <- instead of COMMIT ENTITIES" COMMIT ENTITIES inside a handler      <- framework commits" MODIFY ENTITIES in finalize/check_before_save/save

Real project scenario

A custom program created records in two released SAP RAP BOs — a business partner extension and a follow-up document — and committed after each MODIFY separately. When the second commit failed validation, the first record was already saved, leaving orphans that had to be cleaned up manually every week.
The program was changed to one COMMIT ENTITIES with RESPONSES for both BOs per logical unit, and ROLLBACK ENTITIES when anything failed. Both records are now saved together or not at all, and the weekly clean-up job was retired.

Common mistakes

  • Committing after each BO separately, breaking atomicity across BOs.
  • Using COMMIT WORK instead of COMMIT ENTITIES for RAP changes.
  • Calling COMMIT ENTITIES inside behavior implementations.
  • MODIFY on other BOs during the save phase.
  • Not forwarding the other BO's messages, leaving users with a generic error.
  • One commit for an entire input file, so one bad row blocks everything.

Best practices

  • Change all BOs of one business step in the interaction phase; let one commit save them.
  • In programs: one COMMIT ENTITIES RESPONSES per logical unit, ROLLBACK ENTITIES on failure.
  • Call other teams' or SAP's BOs via released interfaces.
  • Map foreign FAILED/REPORTED into your own responses.
  • Use simulation mode where available to pre-check data.

Interview angle

Questions: "Can one RAP BO change another?", "What is the difference between COMMIT ENTITIES and COMMIT WORK?", "How do you keep two BOs consistent?"
Strong answer: yes, via EML in the interaction phase without local mode; the framework's save sequence covers all changed BOs, so they are saved together or not at all. Programs use COMMIT ENTITIES (runs the save sequence) with RESPONSES for each BO and ROLLBACK ENTITIES on failure; COMMIT WORK and commits inside handlers are wrong. No MODIFY in save-phase methods.

Practice this lesson

Quick check

1. A program changes two RAP BOs that must be saved together. How should it commit?

2. Which EML statement is used to retrieve data from RAP business object instances, including via associations?

3. In a RAP unmanaged scenario, why might a developer explicitly issue the COMMIT ENTITIES statement in EML, for example within an ABAP Unit test?

Interview questions

1. How do two RAP business objects stay consistent when an action in one creates data in the other?

Answer it in your own words first, then compare.

2. A program creates records in two RAP BOs and commits after each. When the second fails, orphans remain. How do you fix the program?

Answer it in your own words first, then compare.

Practice more with Interview AI →

Reference-verified: the steps are checked against official SAP documentation and tutorials, and object and field names in the sample code are checked for consistency. The code has not been compiled or run on an SAP system by ERPClimb. Syntax marked release-dependent varies by SAP release, so check it in your own system.

More lessons in this topic

Interview questions on this topic

Related SAP topics