Using the Entity Manipulation Language to Access Business Objects

Objectives

After completing this lesson, you will be able to:
  • Describe the purpose and syntax of Entity Manipulation Language.
  • Describe the derived data types for RAP Business Objects.
  • Use the Entity Manipulation Language.

Entity Manipulation Language Principle

Features of Entity Manipulation Language (EML)

The Entity Manipulation Language (EML) is a subset of ABAP for accessing RAP business objects (RAP BOs). EML statements allow the data content of a RAP BO (transactional buffer) to be read or modified and the persistent storage of modified data to be triggered.

ABAP EML can be used in all ABAP programs to consume RAP BOs. In particular, they can be used in the implementation of a RAP BO in a behavior implementation (ABAP behavior pool) itself. For the latter, there are some special EML variants.

The execution of an EML statement triggers processes in the RAP runtime framework that call the implementation of the RAP BOs. For unmanaged RAP BOs or unmanaged parts of managed RAP BOs, the implementation is part of an ABAP behavior pool. Otherwise, it is part of the RAP provider framework.

The operands of EML statements are mainly special data objects for passing data to and receiving results or messages from RAP BOs. These data objects are structures and internal tables whose types are tailor-made for this purpose and derived from the RAP BO definition, namely the involved CDS views, and behavior definitions.

Example of EML syntax to create a RAP BO instance

The EML example shows the update of one or several instances of business objects Z00_R_Travel. This business object consists of only one entity, its root entity. The name of the root entity is also Z00_R_Travel.

The update of the BO instances takes place in EML statement MODIFY ENTITIES, where the first occurrence of Z00_R_Travel specifies the business object and the second occurrence of Z00_R_Travel identifies the name of the root entity.

The data changes are not written to the database directly. Instead, they are collected in data buffers on the application server and saved on the database later. The so called save sequence is triggered by EML statement COMMIT ENTITIES. Statement ROLLBACK ENTITIES is available to discard not yet saved changes in case of errors.

Note

Statements COMMIT ENTITIES and ROLLBACK ENTITIES are only needed outside of behavior implementations. When using EML inside a behavior implementation, the RAP runtime framework takes care of the commit and rollback.

The input for the update statement is provided in an internal table named travels after addition WITH.

Note

To simplify the example, we omitted the coding to fill travels.

Internal table travels is a good example of a derived data type. The DATA declaration uses the syntax variant TYPE TABLE FOR, followed by a keyword to specify the purpose of the data object and the name of the BO entity. In our case, the keyword is UPDATE and the name of the entity is Z00_R_Travel. As a result, the travels data object is an internal table which is tailor-made for an update operation on BO entity Z00_R_Travel.

Note

The declaration of data object travel uses TYPE STRUCTURE FOR. It is not meant for use in EML statements, but rather as work area for internal table travels.

Data objects failed and failed_late are also declared with derived data types. They belong to a group of derived types called response types. Response types are always structure types for the entire business object. They are not specific for individual entities or a certain operation like create, update, or delete.

Entity Manipulation Language Commands

Table containing a list of EML Commands with syntax and related derived data types

This overview illustrates the most important EML commands, namely, the basic operations Read, Create, Update, Delete, and the execution of actions. Depending on the operation, the statement expects one or more internal tables as operands for input and output. The data types of these operands are derived data types based on the BO entity and specific for the respective operation.

The most important aspects are as follows:

  • Only the read operation has its own statement, READ ENTITIES. The other operations are variants of the MODIFY ENTITIES statement.
  • The variants of MODIFY ENTITIES are distinguished by a keyword after the name of the entity. READ ENTITIES does not have such a keyword.
  • Operations Read and Execute have several input operands and one output operand for the result. Therefore these operations have more than one related derived types, distinguished by keywords IMPORT, RESULT, LINK, REQUEST.
  • Operations Read, Create, Update, and Delete, only have one operand for input. No IMPORT keyword is needed.
  • The derived types for actions identify the action via the name of the entity and the name of the action, separated by the tilde (~) character.

Derived Data Types

Overview of derived data types for import and result

The structure of derived data types depends on the BO entity and on the operation. Some of them contain all fields of the BO entity. Others contain only the primary key fields.

In our example, the key of the entity consists of two fields, Field1 and Field2. If we look at the derived data types for operation Read, we can see that the result contains all five fields, whereas the derived data type for import contains only the key fields.

Besides the fields of the referenced entity, some derived data types contain extra components. These components are used to exchange additional information in the context of transactional processing. The names of those additional components begin with % to avoid naming conflicts with components of the entities.

The %control component is a substructure which has the same number of components as the BO entity. The names of the components are identical to the field names in the entity but the data type is ABAP_BEHV_FLAG for all components of %control. The %control structure is used in certain cases to specify which fields are requested or provided.

Note

The data element ABAP_BEHV_FLAG serves as a boolean type in the context of RAP. Allowed values are available in structured constant MK of interface IF_ABAP_BEHV.

The technical type of data element ABAP_BEHV_FLAG is RAW(1) and not CHAR(1), as you can expect. Constants ABAP_TRUE, ABAP_FALSE, or literals 'X' and ' ' are not compatible with the type of ABAP_BEHV_FLAG.

Component %cid is needed as a temporary key in situations where the key values of new instances are not provided by the consumer, but calculated by the business object logic (internal numbering). In this case, the %cid value must be populated during Create and used to uniquely identify the instances until the business logic fills the key fields.

If EML operations like Update or Delete need to address instances before the key field values are calculated, they can use the %ref_cid component to identify the instances.

Usually, the code calling the Create operation has to provide the %cid values. Depending on the implementation details, the Create operation or the COMMIT ENTITIESstatement then returns a mapping table for %cid values and the calculated key values.

Hint

There is also an AUTO FILL CID addition. It should only be used if the calling code is not interested in the %cid values.
Component groups in derived types

In addition to the physical components, derived types also contain component groups. The component groups also begin with % and serve the purpose of summarizing groups of table columns under a single name. For example, %data summarizes all elements of the related entity.

Hint

Technically, the component groups are named includes and the components can be addressed by the name of the include.

In the example, field2 is addressed directly as part of the named include %tky, and as part of the named include %data. Because %tky is part of %data, the field can even be addressed as component %tky of named include %data.

Note

Named include %key is obsolete and cannot be used anymore. It has been replaced with %tky. Although in non-draft scenarios, %key and %tky are identical, they differ in draft scenarios, where %tky contains an additional field %is_draft, by which the framework distinguishes draft version and active version of an entity instance.

Response Operands

Response operands used by EML statements

In addition to the input and result operands, EML statements use a set of response operands to provide feedback on the outcome of an operation. While the operand types for input and result are internal tables that depend on the BO entity and the operation, the response operands are deep structures that depend on the business object alone.

Note

Remember that the name of the business object is identical to the name of the root entity.

Receiving responses is always optional and not all responses are available for all EML statements.

EML offers the following response operands:

  • FAILED is used for logging instances for which an operation has failed. The related derived type is RESPONSE FOR FAILED.
  • REPORTED is used for returning messages. These messages are either related to a specific instance or static, that is, independent from a specific data set.
  • MAPPED is used to map the calculated key values of created instances to the provided temporary IDs (component %cid). It is only relevant for CREATE operations.
Overview of derived data types for response

The three response types are deep structures with a table-like component for each entity of the RAP BO.

If we consider a RAP BO with a root entity named Entity1 and a child entity Entity2, then the response types have two components named Entity1 and Entity2. Only the derived type for reported has an additional component named %others, which is also an internal table but with an elementary line type.

Components of response operands

The line types of the table-like components are also derived types, namely the derived types STRUCTURE FOR FAILED <entity name>, STRUCTURE FOR REPORTED <entity name>, and STRUCTURE FOR MAPPED <entity name>.

Note

Be aware of the difference between RESPONSE FOR FAILED <business object> and STRUCTURE FOR FAILED <entity>. RESPONSE FOR FAILED <business object> is based on the entire RAP BO, represented by its root entity and defines a deep structure for the entire RAP BO. STRUCTURE FOR FAILED <entity> is based on a single entity, either root or child.

These types contain the key fields of the related entity plus some generic fields for the details. As usual, the additional fields start with % to avoid naming conflicts.

We discuss some of these additional fields later in this course.

Alias Names for Entities

Aliases for RAP BO entities

In the behavior definition, the name of an entity is derived from the name of the related CDS view entity. In addition, you can provide an alias name for the entity. In the example, the alias Travel is assigned to the entity Z00_R_Travel.

When accessing the business object, in some positions the technical name of an entity can be replaced with the alias name. It can help increase the readability and reusability of code. In the example, the alias Travel is used in an EML statement to identify the entity.

Note

The alias is an alternative name for the entity. It is not an alternative name for the business object. You can use it after keyword ENTITY, but not after keyword OF.

Hint

The ABAP compiler issues a warning if an EML statement uses the technical name of an entity for which an alias exists.

Entity aliases in derived types and behavior pools

Entity alias names are also used in the following places:

  • The alias name is used in response types to identify the table-like component that corresponds to the entity.

  • The alias name is used in the behavior pool as part of the name for the local handler class.

    Note

    For this, it is necessary that the alias name is already known when you invoke the quick fix to generate the behavior pool. If the behavior pool already exists when you introduce the alias name the name of the local class is not adjusted. In that case, you can use the refactoring capabilities of ADT to adjust the class name.

Short and Long Syntax Variant of EML Statements

Long variant versus short variant

The READ ENTITY and MODIFY ENITITY statements are shorter variants of the READ ENTITIES and MODIFY ENTITIES statements.

The short variants are only applicable if you want to address only the root entity of the business object. The short variants omit the ENTITIES OF addition and the subsequent business object name. This is possible because the name of the root entity afterENTITYis sufficient to identify the business object. A drawback of this is that entity alias names are not supported in the short variant.

Note

It is possible and common that the same entity alias name is used in different behavior definitions. Therefore, the entity alias name alone is not enough to identify the business object. The short syntax variant requires the globally unique name of the root entity.

Read and Update a RAP Business Object

In this exercise, you use the Entity Manipulation Language (EML) to read and update a Business Object.

Note

In this exercise, replace ## with your group number.

Template

Repository Object TypeRepository Object ID
ABAP Class/LRN/CL_437T_EML

Solution

Repository Object TypeRepository Object ID
ABAP Class/LRN/CL_437B_EML_S1
Behavior Definition/LRN/437B_R_TRAVEL
ABAP Class (Behavior Pool)/LRN/BP_437B_R_TRAVEL

Task 1: Copy Template

Create a copy of ABAP class /LRN/CL_437T_EML (suggested name: ZCL_##_EML). Replace the values of constants C_AGENCY_ID and C_TRAVEL_ID with the key values of an existing record in your database table Z##_TRAVEL.

Steps

  1. Create a copy of ABAP class /LRN/CL_437T_EML, assign it to your package ZS4D437_## and use the same transport request as before.

    1. In the Project Explorer view, locate class /LRN/CL_437T_EML in package /LRN/S4D437_TEMPLATE and right-click it to open the context menu.

    2. From the context menu, select Duplicate....

    3. Enter the name of your package and the name for the copy. Then choose Next.

    4. Assign the new object to a transport request and choose Finish.

  2. Open your database table Z##_TRAVEL in the Data Preview tool and make a note of the key values for any one of the data records.

    1. Open the database table definition in the editor.

    2. Press F8 to open the Data Preview tool.

    3. Make a note of the values in columns AGENCY_ID and TRAVEL_ID for any one of the displayed records.

  3. Edit the ABAP Class. Replace the placeholder values for the constants C_AGENCY_ID and C_TRAVEL_ID with the values that you determined in the previous step.

    1. Edit the class as usual.

Task 2: Read Data from a Business Object

In your ABAP class, use the EML statement READ ENTITIES to retrieve all fields of one root entity instance of your Business Object Z##_R_TRAVEL. Use the C_AGENCY_ID and C_TRAVEL_ID constants as input to identify the travel that you want to read. Write an error text to the console in case the read access failed.

Steps

  1. In the if_oo_adt_classrun~main method, implement a READ ENTITIES statement for your Business Object Z##_R_TRAVEL to read instances of the root entity.

    1. Insert the following code:

      Code Snippet
      12
      READ ENTITIES OF Z##_R_Travel ENTITY Z##_R_Travel
  2. Read all fields of the instance with AgencyId = c_agency_id and TravelId = c_travel_id.

    Hint

    Use a VALUE expression to identify the instance that you want to read.
    1. Adjust the code as follows:

      Code Snippet
      12345
      READ ENTITIES OF Z##_R_Travel ENTITY Z##_R_Travel ALL FIELDS WITH VALUE #( ( AgencyId = c_agency_id TravelId = c_travel_id ) )
  3. Store the result in a suitably typed data object (suggested name: travels).

    Hint

    Use an inline declaration to make sure the data object has the correct type.
    1. Adjust the code as follows:

      Code Snippet
      123456
      READ ENTITIES OF Z##_R_Travel ENTITY Z##_R_Travel ALL FIELDS WITH VALUE #( ( AgencyId = c_agency_id TravelId = c_travel_id ) ) RESULT DATA(travels)
  4. Retrieve the FAILED response, store it in a suitably typed data object (suggested name: failed) and end the ABAP statement.

    Hint

    Use an inline declaration to make sure the data object has the correct type.
    1. Adjust the code as follows:

      Code Snippet
      1234567
      READ ENTITIES OF Z##_R_Travel ENTITY Z##_R_Travel ALL FIELDS WITH VALUE #( ( AgencyId = c_agency_id TravelId = c_travel_id ) ) RESULT DATA(travels) FAILED DATA(failed).
  5. Evaluate the response. If failed is not initial, write a suitable error text to the console.

    1. After the READ ENTITIES statement, add the following code:

      Code Snippet
      123
      IF failed IS NOT INITIAL. out->write( `Error retrieving the travel` ). ENDIF.
  6. Use the Tooltip Description (F2) to analyze the type of the data object travels.

    1. To display the Tooltip Description, place the cursor on travels and press F2.

  7. Use the Tooltip Description to analyze the type of the data object failed.

    1. To display the Tooltip Description, place the cursor on failed and press F2.

Task 3: Update the Data of a Business Object

If the read access was successful, use the EML statement MODIFY ENTITIES to change the description of the travel. Roll back your changes and write an error text to the console in case the update fails. Commit your changes if the update was successful.

Steps

  1. Add an ELSE branch to the IF...ENDIF control structure and implement a MODIFY ENTITIES statement for the root entity of your business object Z##_R_TRAVEL.

    1. Adjust the code as follows:

      Code Snippet
      1234567
      IF failed IS NOT INITIAL. out->write( `Error retrieving the travel` ). ELSE. MODIFY ENTITIES OF Z##_R_Travel ENTITY Z##_R_Travel ENDIF.
  2. Update the description of the instance with AgencyId = c_agency_id and TravelId = c_travel_id.

    Hint

    Use a VALUE expression to identify the instance that you want to update and to specify the new description.
    1. Adjust the code as follows:

      Code Snippet
      123456
      MODIFY ENTITIES OF Z##_R_Travel ENTITY Z##_R_Travel UPDATE FIELDS ( Description ) WITH VALUE #( ( AgencyId = c_agency_id TravelId = c_travel_id Description = `My new Description` ) )
  3. Retrieve the FAILED response and store it in existing data object failed. Then end the ABAP statement.

    1. Adjust the code as follows:

      Code Snippet
      1234567
      MODIFY ENTITIES OF Z##_R_Travel ENTITY Z##_R_Travel UPDATE FIELDS ( Description ) WITH VALUE #( ( AgencyId = c_agency_id TravelId = c_travel_id Description = `My new Description` ) ) FAILED failed.
  4. Evaluate the response. If failed is initial, execute the statement COMMIT ENTITIES and write a success text to the console. If failed is not initial, execute the statement ROLLBACK ENTITIES and write an error text to the console.

    1. After the MODIFY ENTITIES statement, add the following code:

      Code Snippet
      1234567
      IF failed IS INITIAL. COMMIT ENTITIES. out->write( `Description successfully updated` ). ELSE. ROLLBACK ENTITIES. out->write( `Error updating the description` ). ENDIF.
  5. Activate and test your code as a console application. Display the content of your database table Z##_TRAVEL in the Data Preview tool to confirm that the changed description is stored on the database.

    1. Press Ctrl + F3 to activate the development object.

    2. Press F9 to execute the ABAP class as a console application.

    3. Open the database table and press F8 to open the Data Preview tool.

Task 4: Use Entity Alias

Define an alias for the root entity of your business object, adjust the code where necessary, and analyze the impact on the data object failed. Use the refactoring capabilities of ADT to rename the local class in the behavior pool.

Steps

  1. Navigate to your behavior definition Z##_R_TRAVEL and define an alias for the root entity (suggested name: Travel).

    1. In either the READ ENTITIES or the MODIFY ENTITIES statement, place the cursor on Z##_R_Travel and press F3. Alternatively, hold down the Ctrl key and choose Z##_R_Travel.

    2. In the DEFINE BEHAVIOR FOR statement, remove the comment sign (//) before the ALIAS addition.

    3. Replace the placeholder after alias with Travel.

  2. Activate the behavior definition.

    1. Press Ctrl + F3 to activate the development object.

  3. Return to the ABAP class ZCL_##_EML and perform a syntax check.

    1. Return to the ABAP class, press Ctrl + F2.

    2. The new warnings are listed on the Problems view. You also find warning icons left from the ENTITY additions in the EML statements.

  4. Adjust the EML statements as suggested by the syntax warnings and activate the ABAP class.

    1. After the ENTITY additions in the READ ENTITIES and MODIFY ENTITIES statements, replace Z##_R_Travel with Travel.

    2. Press Ctrl + F3 to activate the development object.

  5. Display the Tooltip Description for data object failed.

    1. Place the cursor on the data object failed (not on the keyword FAILED) and press F2 to display the Tooltip Description.

  6. Edit the behavior pool and rename the local class to lhc_travel.

    1. In the managed statement, place the cursor on the name of the behavior pool zbp_##_r_travel and press F3.

    2. From the tabstrip below the editor, choose Local Types to navigate to the source code of the local class.

    3. Right-click the name of the local class and choose Quick Fix. Alternatively, place the cursor on the name of the local class and press Ctrl + 1.

    4. In the list of available quick fixes, double-click Rename lhc_z##_r_travel.

    5. While the name of the local class is still highlighted, change the name to lhc_travel.

  7. The definition of the get_instance_authorizations method in the behavior pool still uses the name Z##_R_TRAVEL. Replace this name with the alias Travel.

    1. Adjust the code as follows:

      Code Snippet
      12
      METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION IMPORTING keys REQUEST requested_authorizations FOR Travel RESULT result.
  8. Activate the behavior pool.

    1. Press Ctrl + F3 to activate the development object.