EML: Programmatic Access to RAP Business Objects
Entity Manipulation Language, EML, is the ABAP statement set (READ ENTITY, MODIFY ENTITIES, EXECUTE, COMMIT ENTITIES, ROLLBACK ENTITIES) used to interact with a RAP business object from ABAP code instead of through OData. It looks like Open SQL but runs through the RAP runtime, meaning determinations, validations and authorization checks fire, and nothing reaches the database until a COMMIT ENTITIES triggers the save sequence.
This page covers the EML statement set used to read and modify RAP business objects programmatically, from behavior implementations, consumer classes, or unit tests. It focuses on how the transactional buffer and save sequence change the meaning of a READ or MODIFY compared to direct database access, and on the error-handling discipline EML forces on the caller.
Published 16 Sept 2026· 1,497 words
What it is
EML is a small set of ABAP keywords - READ ENTITY, READ ENTITIES OF, MODIFY ENTITY, MODIFY ENTITIES OF, EXECUTE, COMMIT ENTITIES, ROLLBACK ENTITIES - that let ABAP code talk to a RAP business object the same way an OData consumer would, without going through HTTP. Syntactically it resembles Open SQL, with FIELDS, WITH and WHERE-like clauses, which is exactly what causes confusion: it is not a data access statement, it is a call into the generated RAP runtime that dispatches to the behavior implementation class. That means a MODIFY ENTITIES statement runs create/update/delete handler methods, which can in turn run determinations and validations, and none of it touches the database table until an explicit or implicit COMMIT ENTITIES executes the save sequence (finalize, check before save, adjust numbers, save, cleanup). Until that point, everything lives in the transactional buffer, so a READ immediately after a MODIFY in the same LUW sees buffered state, not committed rows.
When to use it
Reach for EML when one RAP business object needs to call another - composition scenarios, cross-BO validations, or a determination that has to read or update an associated root. It is also the right tool for a consumer class outside any UI, a batch job, a legacy interface, or an ABAP unit test, that needs full business-object semantics rather than raw table access. It is not the right tool inside the behavior implementation of an entity to act on that same entity's own instance; use the IMPORTING and CHANGING parameters the framework already hands the handler method, not a self-referential EML call, which invites reentrancy problems. It is also the wrong tool for high-volume data loads where business logic is not required - classic load techniques will outperform EML issued in a loop, and forcing bulk migration through individual EML calls with per-record commits is a common performance mistake.
How it fits the stack
EML sits between a consumer - an OData request handler, another business object's behavior implementation, a report, or a test class - and the behavior implementation class of the target entity. Below EML is the generated runtime infrastructure that resolves the statement into calls on the handler methods, and ultimately the persistence layer touched only during the save sequence. Above EML is the transactional buffer and the save orchestration that decides when data actually reaches the database. It replaces older patterns of a consumer calling a BAPI wrapper function module or reading and writing tables directly: instead of duplicating logic, the consumer goes through the same business object gateway that OData uses. When a RAP business object is exposed via a service binding, the OData handler is itself issuing EML under the hood, so writing EML by hand is only necessary when there is no OData layer in between, such as BO-to-BO calls or automated tests.
A worked example
A nightly batch report has to create a set of custom travel booking header and item records from a legacy interface file, using a RAP business object that already carries the pricing and availability logic in its determinations. Instead of writing a BAPI or inserting rows directly, the report builds an internal table of the fields to create and issues a MODIFY ENTITIES OF statement against the root entity, CREATE FIELDS with that table, capturing MAPPED, FAILED and REPORTED data. It then issues COMMIT ENTITIES, again capturing FAILED and REPORTED tables at the commit step. The report loops over the FAILED table for the create operation and the FAILED table returned by the commit separately, since a record can fail during processing or only at the check-before-save stage; messages from REPORTED are logged against the original interface line using the correlating key the framework returns in MAPPED. Only after both FAILED tables are empty does the report treat a record as successfully posted, which is the discipline EML forces because it never raises an exception for a failed business operation.
How to choose
- EML versus OData round-trip for a consumer that is itself ABAP: EML avoids the HTTP hop and JSON serialization, but it also means the calling code owns error interpretation manually rather than getting an HTTP status; choose EML for internal ABAP-to-BO calls, OData for anything crossing a UI or external boundary.
- EML on the entity's own instance versus using handler parameters: inside a behavior implementation, never call EML back into the entity you are already handling; use the data the framework passed in. Reserve EML for calls into other entities or other business objects.
- One COMMIT ENTITIES per record versus batching: committing per record in a loop creates many small LUWs and defeats the save sequence's ability to batch determinations and checks; batch the MODIFY ENTITIES calls and commit once, or at controlled intervals for very large volumes.
- READ ENTITY versus a direct CDS select: READ ENTITY respects the current transactional buffer, draft state and instance authorization; a direct select is faster but silently bypasses all of that. Use READ ENTITY whenever the result must reflect uncommitted changes or must be authorization-filtered.
- How errors are surfaced: EML never throws for a business error, it populates FAILED and REPORTED tables. An architect should insist that every EML call site has explicit handling of both tables before treating the operation as successful, and that code review checks for this rather than trusting IDE syntax checks.
Common pitfalls
- Not checking the FAILED table after MODIFY ENTITIES or COMMIT ENTITIES: the statement completes without exception even when every record failed, so unchecked code reports success on a batch that inserted nothing.
- Calling EML on the entity's own instance from inside its own behavior implementation, producing recursive or inconsistent runtime behavior that only surfaces under specific trigger sequences, not in a simple developer test.
- Issuing COMMIT ENTITIES inside a loop for mass processing, which passes in a small development test with a handful of records and then performs poorly or times out against production volumes because each iteration runs the full save sequence.
- Assuming READ ENTITY always reflects the database: it reads the transactional buffer, so a READ right after a MODIFY in the same LUW, before commit, returns data that is not yet persisted and would disappear on a rollback.
- Mixing EML calls with direct Open SQL against the same underlying tables in the same program, which lets one code path bypass determinations and validations the other enforces, leaving inconsistent derived fields.
- Writing unit tests that mock away authorization and determinations to make EML calls pass, then discovering in integration testing that a real instance authorization check now fails the same operation the unit test declared successful.
- Targeting a business object that is not released for external or cross-BO consumption: the EML call may compile and run today but is not guaranteed stable, and can break silently on the next upgrade.
ECC, S/4HANA and clean core
EML exists only in the RAP programming model on S/4HANA; there is no ECC equivalent, since ECC business logic is invoked through BAPIs and function modules rather than a generated business-object runtime. From a clean core perspective, EML is the preferred way for custom code to interact with a business object's logic, whether standard or custom, because it goes through the object's published interface rather than touching database tables or internal function modules directly, which keeps custom code stable across upgrades. What is discouraged is using EML against a business object that has not been explicitly released for the intended consumption scenario - doing so trades the illusion of a clean interface for the same fragility as direct table access, just one layer removed.
Whose problem this is
This is developer territory: whoever writes the behavior implementation or the consumer class owns the EML statements and the FAILED and REPORTED handling around them. The architect's involvement is deciding whether a cross-object interaction should go through EML at all, and whether the target business object is meant to be called this way. Handover to functional is limited to confirming the business rules the determinations enforce, not the EML mechanics.
Related SAP objects
Reviewed pages this object connects to in the ERPClimb knowledge graph.
Source: ERPClimb — https://erpclimb.com/sap-technical-topics/entity-manipulation-language-in-rapERPClimb is an independent platform and is not affiliated with SAP SE. Reference pages are written and reviewed by SAP consultants for learning and troubleshooting.