
RAP - Entity Manipulation Language (EML)
In this article we deal with a new language construct to access our RAP Business Object.
Table of contents
How do you easily access a business object from the outside and what does it entail? In this article you will learn more about the new language construct EML and what is behind it. We try to show you the basic concepts and the first possibilities that EML puts at your disposal.
EML
The Entity Manipulation Language is a new SQL-like language construct that allows you to access RAP business objects and their data. All validations, determinations and other settings are taken into account, so that you have the same functions as with the Fiori app. When using you also get full support for actions and the draft functions if they are configured in the object.
READ
In this section we'll talk about reading data from an object, but you have to keep in mind that it's not a SELECT, it's more of a READ. So we have to read the appropriate keys in one way beforehand, there is currently no query function for business objects.
Let's look at two different forms of access, which differ slightly in detail. In the first example, we read all the data for a data record and fill the selection table before accessing it:
DATA:
lt_selection TYPE TABLE FOR READ IMPORT ZBS_I_RAPPartner.
lt_selection = VALUE #(
( PartnerNumber = '1000000001' )
( PartnerNumber = '1000000003' )
).
READ ENTITIES OF ZBS_I_RAPPartner ENTITY Partner
ALL FIELDS WITH lt_selection
RESULT DATA(lt_partner_long)
FAILED DATA(ls_failed)
REPORTED DATA(ls_reported).
out->write( lt_partner_long ).
To do this, we start by defining a table for access that contains the appropriate partner numbers that we want to read. We then call READ ENTITIES to have the result returned for the selection. The second example is a bit shorter because we pass the selection directly. In this example we only read some fields of the entity:
READ ENTITIES OF ZBS_I_RAPPartner ENTITY Partner
FIELDS ( PartnerName Street City ) WITH VALUE #(
( PartnerNumber = '1000000001' )
( PartnerNumber = '1000000003' )
)
RESULT DATA(lt_partner_short)
FAILED ls_failed
REPORTED ls_reported.
out->write( lt_partner_short ).
After the selection has been made and the output has been made to the console, you will receive the following result. The upper result is the long form, below the short form. The resulting table of results always represents the entire entity:
So what is it about the individual components of the statement, briefly explained here:
- READ ENTITIES - Specification of the RAP business object, usually corresponds to the root node of the object.
- ENTITY - Specification of the entity to be read from the RAP object, the alias of the entity is particularly important here.
- FIELDS - Specification of the fields to be read as a table, expression of the fields or all fields.
- WITH - pass the keys to the read function, table is defined with "TABLE FOR READ IMPORT".
- RESULT - Table with the read data, can be created using an inline declaration and has the type "TABLE FOR READ RESULT".
- FAILED - Key of the erroneous entries if reading did not work.
- REPORTED - Contains error messages when there are problems reading.
CREATE
In the next step, we want to create a new data record, for this there is the statement MODIFY ENTITIES, which contains all important operations (Create, Update, Delete, Action). In our example, we fill a table again, this time of the "TABLE FOR CREATE" type, since we want to create a new data record. The following example:
DATA:
lt_creation TYPE TABLE FOR CREATE ZBS_I_RAPPartner.
lt_creation = VALUE #(
(
%cid = 'DummyKey1'
PartnerNumber = '1000000007'
PartnerName = 'Amazon'
Country = 'US'
%control-PartnerNumber = if_abap_behv=>mk-on
%control-PartnerName = if_abap_behv=>mk-on
%control-Country = if_abap_behv=>mk-on
)
).
MODIFY ENTITIES OF ZBS_I_RAPPartner ENTITY Partner
CREATE FROM lt_creation
FAILED ls_failed
MAPPED DATA(ls_mapped)
REPORTED ls_reported.
TRY.
out->write( ls_mapped-partner[ 1 ]-PartnerNumber ).
COMMIT ENTITIES.
CATCH cx_sy_itab_line_not_found.
out->write( ls_failed-partner[ 1 ]-%cid ).
ENDTRY.
What you will notice when filling the table is that we not only take over the data fields, but also fill in the CID and CONTROL fields. These fields are important so that the data in the object is correctly transferred:
- %CID - Dummy ID identifying a record within Create, Update and Delete. Can be assigned freely, but should be unambiguous.
- %CONTROL - Specifies which fields are taken into account during the operation. If the fields in the structure are not active, no data is transferred and the new data record is empty.
- MAPPED - return the changed key and mapping from CID to table key. Especially important when the keys are generated within the business object.
Finally, the new key is output in the log and a COMMIT ENTITIES is sent. This roughly corresponds to COMMIT WORK in ABAP, but is used specifically for RAP operations.
UPDATE
In the last step we created a relatively incomplete data set on the database, which we now want to enrich with some data. In addition, for the initial situation, the current data record on the database:
To do this, we define a table of the "TABLE FOR UPDATE" type suitable for the action and fill in the required fields. We don't have to specify a CID for the update because the key is already known. However, we should also specify the appropriate key. Furthermore, the CONTROL structure is important again. This results in the following code:
DATA:
lt_update TYPE TABLE FOR UPDATE ZBS_I_RAPPartner.
lt_update = VALUE #(
(
PartnerNumber = '1000000007'
PartnerName = 'Amazon Fake'
City = 'Seattle'
PaymentCurrency = 'USD'
%control-PaymentCurrency = if_abap_behv=>mk-on
%control-City = if_abap_behv=>mk-on
)
).
MODIFY ENTITIES OF ZBS_I_RAPPartner ENTITY Partner
UPDATE FROM lt_update
FAILED ls_failed
MAPPED ls_mapped
REPORTED ls_reported.
IF ls_failed-partner IS INITIAL.
out->write( 'Updated' ).
COMMIT ENTITIES.
ENDIF.
As you can see in the example above, we also pass a new name for the partner, but do not fill the CONTROL structure. So we assume that the Name field is not updated and keeps the original value. After running the code, we get the following result, and our guess is true:
IF_ABAP_BEHV
In our examples we had already used constants from the interface IF_ABAP_BEHV. The interface provides various constants for use around the behavior implementation and also provides information about where these constants can be used via ABAP Docs. Here is an example of the MK constants used:
Usage
Where do you actually need EML? Above all, it is used for external access to the business object, as our examples are currently structured. Later there will be many RAP objects that function as BAPIs in the system, so you have to address them in this way. Furthermore, RAP is also used within the business object if you implement validations, determinations or actions, since you have to access and change data from the BO again and again.
Complete example
As always, at the end the complete source code of the example, you can also find the whole thing via commit in the corresponding GitHub repository from us:
CLASS zcl_bs_demo_simple_eml DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_bs_demo_simple_eml IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA:
lt_selection TYPE TABLE FOR READ IMPORT ZBS_I_RAPPartner,
lt_creation TYPE TABLE FOR CREATE ZBS_I_RAPPartner,
lt_update TYPE TABLE FOR UPDATE ZBS_I_RAPPartner.
" Long form for selection (ALL FIELDS)
lt_selection = VALUE #(
( PartnerNumber = '1000000001' )
( PartnerNumber = '1000000003' )
).
READ ENTITIES OF ZBS_I_RAPPartner ENTITY Partner
ALL FIELDS WITH lt_selection
RESULT DATA(lt_partner_long)
FAILED DATA(ls_failed)
REPORTED DATA(ls_reported).
out->write( lt_partner_long ).
" Short form for selection (SOME FIELDS)
READ ENTITIES OF ZBS_I_RAPPartner ENTITY Partner
FIELDS ( PartnerName Street City ) WITH VALUE #(
( PartnerNumber = '1000000001' )
( PartnerNumber = '1000000003' )
)
RESULT DATA(lt_partner_short)
FAILED ls_failed
REPORTED ls_reported.
out->write( lt_partner_short ).
" Create new partner
lt_creation = VALUE #(
(
%cid = 'DummyKey1'
PartnerNumber = '1000000007'
PartnerName = 'Amazon'
Country = 'US'
%control-PartnerNumber = if_abap_behv=>mk-on
%control-PartnerName = if_abap_behv=>mk-on
%control-Country = if_abap_behv=>mk-on
)
).
MODIFY ENTITIES OF ZBS_I_RAPPartner ENTITY Partner
CREATE FROM lt_creation
FAILED ls_failed
MAPPED DATA(ls_mapped)
REPORTED ls_reported.
TRY.
out->write( ls_mapped-partner[ 1 ]-PartnerNumber ).
COMMIT ENTITIES.
CATCH cx_sy_itab_line_not_found.
out->write( ls_failed-partner[ 1 ]-%cid ).
ENDTRY.
" Update partner
lt_update = VALUE #(
(
PartnerNumber = '1000000007'
PartnerName = 'Amazon Fake'
City = 'Seattle'
PaymentCurrency = 'USD'
%control-PaymentCurrency = if_abap_behv=>mk-on
%control-City = if_abap_behv=>mk-on
)
).
MODIFY ENTITIES OF ZBS_I_RAPPartner ENTITY Partner
UPDATE FROM lt_update
FAILED ls_failed
MAPPED ls_mapped
REPORTED ls_reported.
IF ls_failed-partner IS INITIAL.
out->write( 'Updated' ).
COMMIT ENTITIES.
ENDIF.
ENDMETHOD.
ENDCLASS.
Conclusion
With EML, you first have to learn some new language constructs and how they work exactly. The new table types can also be overwhelming at first and some of the content makes no sense at first. But once you get into the language, it's fun to work with. In a later article we will delve even deeper into the topic of EML, here are just the basics for the following articles.