EML Part 2: %cid, %cid_ref, MAPPED, FAILED and REPORTED
Master the correlation and response side of EML: %cid and %cid ref for linking new instances, deep creates, MAPPED for final keys, FAILED with %fail-cause, and REPORTED messages — and how to evaluate them correctly.
Explanation
📌 KEY POINTS
✅ %cid names a new instance; %cid_ref refers to it.
✅ MAPPED returns new keys; FAILED has %fail-cause; REPORTED has messages.
✅ Deep create: header + items in one MODIFY.
⚠️ Evaluate responses after MODIFY and after COMMIT.
▶ WHERE WE ARE
Part 1 introduced the statements. When you create several related instances at once, you need a way to refer to things that do not have keys yet, and afterwards you need to know what happened to each instance. That is the job of content IDs and response parameters.
- %CID — A NAME FOR SOMETHING THAT HAS NO KEY YET
When you create an instance, its key may be assigned by the BO (UUID, number range, late numbering). You cannot refer to it by key within the same request, so you give it a content ID: %cid = 'REQ1'. %cid values are your choice, must be unique within one request, and live only for that request.
- %CID_REF — REFERRING TO A NEW INSTANCE
In the same MODIFY, other operations can refer to the new instance through %cid_ref:
- CREATE BY \_Item … %cid_ref = 'REQ1' — create items for the request being created (deep create).
- EXECUTE submit FROM VALUE #( ( %cid_ref = 'REQ1' ) ) — execute an action on it.
- UPDATE … %cid_ref = 'REQ1' — change it again.
Each item in %target also gets its own %cid so you can find its key in MAPPED.
━━━━━━━━━━━━━━━━━━━━
▶ 3. MAPPED — THE KEYS YOU DID NOT KNOW
After the MODIFY, MAPPED contains one line per created instance per entity: mapped-purchaserequest (with %cid and the key / %tky), mapped-item. Use it to read the new instances, to log their keys, or to pass them on. With late numbering, MAPPED contains %pid during the interaction phase; final keys exist only after the save (use COMMIT ENTITIES … and CONVERT KEY or read the saved data).
━━━━━━━━━━━━━━━━━━━━
▶ 4. FAILED — WHAT DID NOT WORK
- One component per entity: failed-purchaserequest, failed-item.
- Each line identifies the instance (%tky, or %cid for creates) and %fail-cause: not_found, unauthorized, locked, conflict (e.g. ETag), disabled (feature control), readonly, unspecific.
- An instance in FAILED was not processed; the rest of the request may have been.
━━━━━━━━━━━━━━━━━━━━
▶ 5. REPORTED — WHY
- Messages per entity (reported-purchaserequest with %tky / %cid and %msg), plus reported-%other for unbound messages.
- %msg is an object implementing if_abap_behv_message; get the text with %msg->if_message~get_text( ) and the severity with %msg->m_severity.
- %element shows which fields a message refers to.
━━━━━━━━━━━━━━━━━━━━
▶ 6. EVALUATE AT THE RIGHT TIME
- After MODIFY: interaction-phase results — authorization, feature control, prechecks, action failures, determinations on modify.
- After COMMIT ENTITIES RESPONSE: save-phase results — validations and on-save determinations. A request that passed MODIFY can still fail at COMMIT.
Programs should evaluate both.
━━━━━━━━━━━━━━━━━━━━
▶ 7. DEEP CREATE — ALL IN ONE STATEMENT
A header with items is created in one MODIFY: CREATE for the root with %cid, CREATE BY \_Item with %cid_ref and %target. RAP processes them together; either the whole tree passes the save sequence or nothing is saved.
━━━━━━━━━━━━━━━━━━━━
▶ STEP BY STEP
- Run the code example: deep create with two items plus an action on the new request.
- Print MAPPED to see the keys, then force a failure (omit the description) and print FAILED and REPORTED after COMMIT.
- Write a reusable method that converts FAILED/REPORTED into a readable log.
━━━━━━━━━━━━━━━━━━━━
▶ WHAT YOU HAVE AFTER PART 2
You can create complex data in one call and understand the outcome of every instance. Part 3 explains IN LOCAL MODE.
Code example
" ===== Deep create + action on the new instance in ONE MODIFY =====MODIFY ENTITIES OF zr_purchreq ENTITY PurchaseRequest CREATE FIELDS ( Description CurrencyCode ) WITH VALUE #( ( %cid = 'REQ1' Description = 'Laptops' CurrencyCode = 'EUR' ) ) CREATE BY \_Item FIELDS ( ItemNo ItemText Quantity Unit Price CurrencyCode ) WITH VALUE #( ( %cid_ref = 'REQ1' " parent = new header %target = VALUE #( ( %cid = 'ITM1' ItemNo = '0010' ItemText = 'Laptop' Quantity = 3 Unit = 'ST' Price = '1200.00' CurrencyCode = 'EUR' ) ( %cid = 'ITM2' ItemNo = '0020' ItemText = 'Docking station' Quantity = 3 Unit = 'ST' Price = '180.00' CurrencyCode = 'EUR' ) ) ) ) ENTITY PurchaseRequest EXECUTE submit FROM VALUE #( ( %cid_ref = 'REQ1' ) ) " action on the new instance MAPPED DATA(mapped) FAILED DATA(failed) REPORTED DATA(reported). " ===== MAPPED: which key did each %cid get? =====LOOP AT mapped-purchaserequest INTO DATA(m_req). out->write( |Request %cid { m_req-%cid } -> UUID { m_req-RequestUUID }| ).ENDLOOP.LOOP AT mapped-item INTO DATA(m_item). out->write( |Item %cid { m_item-%cid } -> UUID { m_item-ItemUUID }| ).ENDLOOP. " ===== Interaction-phase failures =====LOOP AT failed-purchaserequest INTO DATA(f). out->write( |Failed: cid { f-%cid } cause { f-%fail-cause }| ).ENDLOOP. " ===== Save phase: validations only run now =====COMMIT ENTITIES RESPONSE OF zr_purchreq FAILED DATA(commit_failed) REPORTED DATA(commit_reported). " ===== Reusable message evaluation =====LOOP AT commit_reported-purchaserequest INTO DATA(r). out->write( |{ r-%msg->m_severity }: { r-%msg->if_message~get_text( ) }| ).ENDLOOP.LOOP AT commit_reported-item INTO DATA(ri). out->write( |Item: { ri-%msg->if_message~get_text( ) }| ).ENDLOOP. " %fail-cause values (if_abap_behv=>cause-...):" not_found | unauthorized | locked | conflict | disabled | readonly | unspecificReal project scenario
A data migration program created purchase request headers in one MODIFY, committed, then tried to find the new headers by selecting the latest rows from the table to attach items. Under parallel load it attached items to the wrong headers.
Rewriting it as a deep create — header with %cid, items with %cid_ref in the same MODIFY — removed the guessing completely. MAPPED gave the program the exact keys for its log, and a failed validation now rejected a header together with its items instead of leaving headers without items.
Common mistakes
- Guessing new keys by selecting "the latest" rows instead of using MAPPED.
- Reusing the same %cid twice in one request.
- Confusing %cid (name of a new instance) with %cid_ref (reference to it).
- Evaluating only MODIFY responses and ignoring COMMIT ENTITIES RESPONSE.
- Ignoring %fail-cause, so every failure looks the same.
- Expecting final late-numbering keys in MAPPED before the save.
Best practices
- Create related data in one deep MODIFY with %cid / %cid_ref.
- Give every created instance a unique, readable %cid (e.g. row number of the input).
- Evaluate FAILED and REPORTED after MODIFY and after COMMIT.
- Build one reusable method that turns responses into a log.
- Use %fail-cause to react correctly (retry on locked, reload on conflict).
Interview angle
Questions: "What is %cid and %cid_ref?", "How do you do a deep insert in EML?", "What is in MAPPED, FAILED and REPORTED?", "When do validation errors appear in EML?"
Strong answer: %cid names a new instance within one request; %cid_ref refers to it from other operations such as create-by-association or an action. MAPPED returns keys per %cid, FAILED lists failed instances with %fail-cause, REPORTED carries messages. Interaction-phase failures show after MODIFY; validation failures after COMMIT ENTITIES RESPONSE. A deep create keeps the tree consistent in one transaction.
Practice this lesson
Quick check
1. A program creates headers and then needs their keys to add items. What is the correct approach?
2. Which EML response parameter provides the actual message texts (e.g., error, warning, success) generated during processing of an entity operation?
3. How can a deep create be performed in EML to create a child instance together with its parent in one statement chain?
Interview questions
1. Your EML MODIFY returns no FAILED entries, but the data is not saved. Why, and how should the program evaluate results?
Answer it in your own words first, then compare.
2. Explain %cid, %cid_ref, MAPPED, FAILED and REPORTED using a deep create of a header with two items.
Answer it in your own words first, then compare.
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.