无常笔记ABAP Cheat Sheets中文导读全站搜索

英文原文:SAP-samples · 上游版本 d43eb13c4c7c · 原始 Markdown

ABAP for RAP: Entity Manipulation Language (ABAP EML)

RAP Terms

ABAP Entity Manipulation Language (or EML for short) is a subset of ABAP that allows you to access the data of RAP business objects in an ABAP program. The following points cover RAP-related terms such as RAP business objects and others for setting the context:

Terms Notes

RAP business objects (RAP BO)

RAP behavior definition (BDEF)

Transactional buffer and implementation types

  • A BDEF defines the behavior of a RAP BO and, thus, how to handle its data. This data is available in the RAP transactional buffer.
  • It is a storage for a RAP BO's data that is used and worked on during an SAP LUW.
  • This data includes RAP BO instances (i. e. concrete data sets of an entity). This is where EML enters the picture: EML is used, among others, to access this data in the transactional buffer.
  • Currently, there are two kinds of RAP BOs: managed and unmanaged RAP BOs.
  • Managed and unmanaged are implementation types that are also specified in the BDEF.
  • The implementation type determines the RAP BO provider, i. e. how the transactional buffer is provided and how the behavior of a RAP BO is implemented.

Managed RAP BOs

  • The managed RAP BO provider fully or partly provides the transactional buffer and RAP BO behavior (for standard operations only). In this case, the developers need not cater for the transactional buffer and implement the standard operations. This implementation is mostly relevant for greenfield scenarios when starting from scratch.
  • Example: Regarding CRUD operations in managed RAP BOs, developers need not cater for an implementation at all. The standard operations work out of the box. For example, in case of an update operation, RAP BO instance data that is to be updated is automatically read into the transactional buffer, and then updated accordingly there. Finally, when triggering the saving, the updated instance in the transactional buffer is automatically saved to the database without any custom development needed.
  • The transactional buffer is provided, too. You do not need to create the buffer yourself.
  • Note: Usually, the behavior of a RAP BO requires some additional implementations also in the context of managed RAP BOs. For example, non-standard operations or feature controls must be self-implemented in ABAP behavior pools (see the details further down).

Unmanaged RAP BOs

  • Everything must be provided by the unmanaged RAP BO provider, i. e. the transactional buffer and all RAP BO operations must be provided or self-implemented by developers in an ABAP behavior implementation
  • Unmanaged RAP BOs are, for example, relevant for brownfield scenarios, i. e. in scenarios in which transactional buffers and application logic is already available and should be embedded in the RAP world. Note that it is possible to have a managed RAP BO with unmanaged parts, e.g. unmanaged save or additional save. Find more information here.

ABAP behavior implementation in an ABAP behavior pool (ABP)

  • An ABAP behavior pool is a special class pool for an ABAP behavior implementation that implements the unmanaged RAP BO provider based on definitions in a BDEF. The class pool's name is specified in the BDEF.
  • The global class of a behavior pool does not implement the behavior itself. It is empty on creation apart from the declaration and implementation part skeletons. The behavior implementation is coded in local RAP handler classes and a RAP saver class in the CCIMP include of the behavior pool. These classes are called by the RAP runtime engine when the RAP BO is accessed. This is covered in more detail further down.
  • Usually, saver classes are not needed in managed RAP BOs (except for special variants of managed RAP BOs such as RAP additional save and RAP unmanaged save). Local handler classes are usually needed in managed RAP BOs if implementations are required that go beyond standard operations.
  • Note: In more complex scenarios, with RAP BOs that consist of many entities, you can define behavior pools for individual entities by adding the syntax to the define behavior for notation. There is not a saver class for each entity but only one saver class for the BO as a whole. Any number of behavior pools can be assigned to a BDEF allowing applications a structuring into multiple units.

[!NOTE]

⬆️ back to top

RAP Behavior Definition (BDEF)

⬆️ back to top

ABAP Behavior Pools (ABP)

You can access RAP BO data from inside AS ABAP using EML. Among other things, EML allows you to read or modify RAP BOs by accessing the RAP BO data (the RAP BO instances) in the transactional buffer and trigger the persistent storage or reset changes. More precisely, when EML statements are executed, the calling of RAP handler methods is triggered to access the transactional buffer of a RAP BO. As mentioned, for unmanaged RAP BOs or unmanaged parts of managed RAP BOs, the handler methods that are called are part of an ABAP behavior pool.

The global class of an ABP has the addition FOR BEHAVIOR OF bdef to the definition while bdef stands for the name of the BDEF. This class is (initially) empty apart from the declaration and implementation part skeleton.

CLASS zbp_demo_abap_rap_draft_m DEFINITION PUBLIC ABSTRACT FINAL FOR BEHAVIOR OF zdemo_abap_rap_draft_m.
ENDCLASS.

CLASS zbp_demo_abap_rap_draft_m IMPLEMENTATION.
ENDCLASS.

The actual implementation is done in local classes in the CCIMP include (Local Types tab in ADT) of the behavior pool. There, two kinds of local classes are to be defined and implemented that are related to the RAP BO's runtime: one or more handler classes to implement the RAP BO behavior (in RAP handler methods) during the RAP interaction phase (the data reading and modification phase) and a saver class to implement the RAP save sequence (in saver methods to save data from the transactional buffer to the database).

⬆️ back to top

RAP Handler Classes and Methods

Example: Handler class definition

CLASS lhc_root DEFINITION INHERITING FROM cl_abap_behavior_handler.
...
ENDCLASS.

Example: Handler method definitions

"Create
METHODS create FOR MODIFY
      IMPORTING entities FOR CREATE bdef.

"Read: Specifying a read result is mandatory.
METHODS read FOR READ
      IMPORTING keys FOR READ bdef RESULT result.

"Action: action name is preceded by the BDEF name and a tilde after FOR ACTION
METHODS some_action FOR MODIFY
      IMPORTING keys FOR ACTION bdef~some_action.

⬆️ back to top

Parameters of Handler Methods

[!NOTE]
It is essential to implement RAP handler methods correctly to ensure the stability and consistency of RAP business objects, particularly in populating the RAP response parameters. For more details on best practices for implementation, refer to the documentation.

⬆️ back to top

RAP Saver Class and Saver Methods

Example: Definition of a RAP saver class and saver methods

CLASS lsc_bdef DEFINITION INHERITING FROM cl_abap_behavior_saver.
  PROTECTED SECTION.

    "For final calculations and data modifications involving all
    "BOs in the current RAP transaction
    METHODS finalize REDEFINITION.

    "Checks the consistency of the transactional buffer before
    "the save method saves data to the database
    METHODS check_before_save REDEFINITION.

    "Preliminary IDs are mapped to final keys. Only for late numbering.
    METHODS adjust_numbers REDEFINITION.

    "Saves the current state of the transactional buffer to the database
    METHODS save REDEFINITION.

    "Clear the transactional buffer
    METHODS cleanup REDEFINITION.
    METHODS cleanup_finalize REDEFINITION.

ENDCLASS.

⬆️ back to top

ABP Auxiliary Classes

⬆️ back to top

BDEF Derived Types

The operands of EML statements and parameters of handler and saver methods are mainly special messenger tables for passing data and receiving results or messages, i. e. the communication between a RAP BO consumer and the RAP BO provider using EML consists (in most cases) of exchanging data stored in internal tables that have special ABAP types - BDEF derived types. These types are tailor-made for RAP purposes.

As the name implies, the types are derived by the ABAP runtime framework from CDS entities and their behavior definition in the BDEF. With these special types, a type-safe access to RAP BOs is guaranteed.

[!NOTE]

⬆️ back to top

BDEF Derived Type Syntax and Declaring Data Types and Data Objects

[!NOTE]
Certain types derived from the BDEF can only be specified and used within implementation classes, not beyond. These types include the following: FOR CHANGE, FOR DETERMINATION, FOR VALIDATION, FOR ... FEATURES, FOR ... AUTHORIZATION.

BDEF derived type examples:

[!NOTE]
The demo BDEF zdemo_abap_rap_ro_m ...

*&---------------------------------------------------------------------*
*& BDEF derived types demonstrating long and short forms
*&---------------------------------------------------------------------*

"Short forms
"Specifying the RAP BO root entity
TYPES t1 TYPE TABLE FOR CREATE zdemo_abap_rap_ro_m.
DATA d1 TYPE TABLE FOR CREATE zdemo_abap_rap_ro_m.
"Specifying child entity
TYPES t2 TYPE TABLE FOR UPDATE zdemo_abap_rap_ch_m.
DATA d2 TYPE TABLE FOR UPDATE zdemo_abap_rap_ch_m.

"Long form: Specifying the name of the RAP BO root entity, followed
"by \\ and an entity of the composition tree
"Since an alias name is specified for the example entities, it must
"be specified after \\. Otherwise, the entity name can be specified.
"t3/d3 are the same as t1/d1.
TYPES t3 TYPE TABLE FOR CREATE zdemo_abap_rap_ro_m\\root.
DATA d3 TYPE TABLE FOR CREATE zdemo_abap_rap_ro_m\\root.
"In this example, t4/d4 are the same as t2/d2.
TYPES t4 TYPE TABLE FOR UPDATE zdemo_abap_rap_ro_m\\child.
DATA d4 TYPE TABLE FOR UPDATE zdemo_abap_rap_ro_m\\child.

"Specifying associations that are declared in the BDEF preceded by \
"with both short and long forms
"In this example, t5/d5 are the same as t6/d6.
TYPES t5 TYPE TABLE FOR CREATE zdemo_abap_rap_ro_m\_child.
DATA d5 TYPE TABLE FOR CREATE zdemo_abap_rap_ro_m\_child.
TYPES t6 TYPE TABLE FOR CREATE zdemo_abap_rap_ro_m\\root\_child.
DATA d6 TYPE TABLE FOR CREATE zdemo_abap_rap_ro_m\\root\_child.
"In this example, t7/d7 are the same as t8/d8.
TYPES t7 TYPE TABLE FOR READ IMPORT zdemo_abap_rap_ro_m\\child\_parent.
DATA d7 TYPE TABLE FOR READ IMPORT zdemo_abap_rap_ro_m\\child\_parent.
TYPES t8 TYPE TABLE FOR READ IMPORT zdemo_abap_rap_ch_m\_parent.
DATA d8 TYPE TABLE FOR READ IMPORT zdemo_abap_rap_ch_m\_parent.

*&---------------------------------------------------------------------*
*& Miscellaneous BDEF derived types
*&---------------------------------------------------------------------*

"The examples show a selection of possible types. The types mostly use
"the short form.

*&---------------------------------------------------------------------*
*& Table types
*&---------------------------------------------------------------------*

"Create
DATA create_tab TYPE TABLE FOR CREATE zdemo_abap_rap_ro_m.

"Update
DATA update_tab TYPE TABLE FOR UPDATE zdemo_abap_rap_ro_m.

"Create-by-association operation specifying the name of the entity
"and the association
DATA cba_tab TYPE TABLE FOR CREATE zdemo_abap_rap_ro_m\_child.

"Action; the name of the action is preceded by a tilde
DATA action_import TYPE TABLE FOR ACTION IMPORT zdemo_abap_rap_ro_m~multiply_by_2.
"The example action does not specify a result parameter, therefore the following
"type is not available.
"DATA action_result TYPE TABLE FOR ACTION RESULT zdemo_abap_rap_ro_m~multiply_by_2.

"Read
DATA read_import TYPE TABLE FOR READ IMPORT zdemo_abap_rap_ro_m.
DATA read_result TYPE TABLE FOR READ RESULT zdemo_abap_rap_ro_m.

"The previous examples use the RAP BO root entity. The following ones
"use a child entity specified in the example BDEF.
"Update
DATA update_tab_ch TYPE TABLE FOR UPDATE zdemo_abap_rap_ch_m.
"Which corresponds to the long form sepcifying the RAP BO root entity
"name and the (alias) name of the child entity followed by \\
DATA update_tab_ch_2 TYPE TABLE FOR UPDATE zdemo_abap_rap_ro_m\\child.
DATA delete_tab_ch TYPE TABLE FOR DELETE zdemo_abap_rap_ch_m.
"Read-by-association
DATA rba_import_child_to_parent TYPE TABLE FOR READ IMPORT zdemo_abap_rap_ch_m\_parent.
DATA rba_import_child_to_parent_2 TYPE TABLE FOR READ IMPORT zdemo_abap_rap_ro_m\\child\_parent.
DATA rba_result_child_to_parent TYPE TABLE FOR READ RESULT zdemo_abap_rap_ch_m\_parent.
DATA rba_result_child_to_parent_2 TYPE TABLE FOR READ IMPORT zdemo_abap_rap_ro_m\\child\_parent.

*&---------------------------------------------------------------------*
*& Structured types
*&---------------------------------------------------------------------*

DATA create_wa TYPE STRUCTURE FOR CREATE zdemo_abap_rap_ro_m.
DATA update_wa TYPE STRUCTURE FOR UPDATE zdemo_abap_rap_ro_m.
TYPES delete_wa TYPE STRUCTURE FOR DELETE zdemo_abap_rap_ro_m.
DATA update_child_wa TYPE STRUCTURE FOR UPDATE zdemo_abap_rap_ch_m.
TYPES delete_child_wa TYPE STRUCTURE FOR DELETE zdemo_abap_rap_ch_m.

"Retrieving permissions
DATA perm_req TYPE STRUCTURE FOR PERMISSIONS REQUEST zdemo_abap_rap_ro_m.

"Retrieving global features
"... FOR ... FEATURES ... can only be used within implementation classes
"DATA feat_req TYPE STRUCTURE FOR GLOBAL FEATURES RESULT zdemo_abap_rap_ro_m.

"The same applies to validations and determinations
"DATA validate TYPE TABLE FOR VALIDATION zdemo_abap_rap_ro_m~val.
"DATA determine TYPE TABLE FOR DETERMINATION zdemo_abap_rap_ro_m~det_add_text.

*&---------------------------------------------------------------------*
*& BDEF derived types relating to RAP response parameters
*&---------------------------------------------------------------------*

"Response parameters
"Note: The addition EARLY or no addition is relevant in the context of the
"RAP interaction phase. The addition LATE is relevant in the context of the
"save phase.
DATA map TYPE RESPONSE FOR MAPPED zdemo_abap_rap_ro_m.
DATA fail TYPE RESPONSE FOR FAILED zdemo_abap_rap_ro_m.
DATA resp TYPE RESPONSE FOR REPORTED zdemo_abap_rap_ro_m.
"Same as resp
DATA resp_2 TYPE RESPONSE FOR REPORTED EARLY zdemo_abap_rap_ro_m.
"Relevant for the late RAP save phase
DATA map_late TYPE RESPONSE FOR MAPPED LATE zdemo_abap_rap_ro_m.
DATA fail_late TYPE RESPONSE FOR FAILED LATE zdemo_abap_rap_ro_m.
DATA resp_late TYPE RESPONSE FOR REPORTED LATE zdemo_abap_rap_ro_m.

"You can check the F2 information in ADT for the types. The types above
"are deep structures, containing tables typed with TYPE TABLE FOR MAPPED
"and so on.
DATA map_tab_early_1 TYPE TABLE FOR MAPPED zdemo_abap_rap_ro_m.
DATA map_tab_early_2 TYPE TABLE FOR MAPPED EARLY zdemo_abap_rap_ro_m.
DATA map_tab_late TYPE TABLE FOR MAPPED LATE zdemo_abap_rap_ro_m.

*&---------------------------------------------------------------------*
*& BDEF derived types relating to the save phase in RAP additional
*& and unmanaged save scenarios
*&---------------------------------------------------------------------*

"REQUEST FOR ... can only be used within implementation classes
"For create and update operations
"DATA req_change TYPE REQUEST FOR CHANGE zdemo_abap_rap_ro_m_as.
"For delete operations
"DATA req_delete TYPE REQUEST FOR DELETE zdemo_abap_rap_ro_m_as.

*&---------------------------------------------------------------------*
*& Excursion: Typing method parameters with BDEF derived types
*&---------------------------------------------------------------------*

"TYPES tab_type TYPE TABLE FOR CREATE zdemo_abap_rap_ro_m.
"METHODS some_meth IMPORTING itab TYPE tab_type.

⬆️ back to top

Components of BDEF Derived Types

Many of the BDEF derived types contain components of CDS entities like key and data fields that retain their original data type, for example, a messenger table typed with TYPE TABLE FOR CREATE. Certainly, if an instance is to be created, key and field values of a RAP BO instance are of relevance.

Yet, all BDEF derived types contain special RAP components serving a dedicated purpose. The names of these RAP components begin with % to avoid naming conflicts with components of the CDS entities. The following image shows the F2 information of a BDEF derived type containing the % components and fields from the CDS entity.

BDEF_derived_types

Some of the % components are component groups summarizing groups of table columns under a single name. In doing so, they simplify the handling of derived types for developers. For example, the component group %data contains all primary key and data fields of a RAP BO entity (actually, by containing the keys, it also contains the component group %key in the case above). The F2 information in ADT helps you find out about the available components in a variable. The image below shows the details of %data when clicking the derived type link in the first ADT F2 information screen.

BDEF_derived_type_components

The availability of % components depends on definitions in the BDEF. Their availability also depends on more criteria, for example, the scenario. For example, the component %pid that represents a preliminary ID for a RAP BO instance is only available in late numbering scenarios. The draft indicator %is_draft is only relevant in the context of draft.

The following table covers a selection of available BDEF derived type components. Find more details on the available components in section Components of BDEF Derived Types of the ABAP Keyword Documentation.

Component Notes Code Snippet

%cid, %cid_ref

  • %cid is a string to define a content ID.
  • Content IDs are used as a unique and preliminary identifier for RAP BO operations in which instances are created and especially in cases where the key values of RAP BO instances are not yet determined
  • Assume that you create a RAP BO instance with an EML create request and the key value has not yet been determined. In the same request - a save has not yet been triggered - an update is requested for this RAP BO instance. Using the content ID, it is guaranteed that the update operation happens for the desired instance. For this purpose, derived types for operations like update or delete include the component %cid_ref to refer to the content ID %cid as the name implies.
  • Note: You should always fill %cid even if not needed. The specified content ID is only valid within one ABAP EML request. You can use the optional addition AUTO FILL CID in EML modify operations to create %cid automatically. However, if you use this addition, you cannot refer to %cid in subsequent operations.
MODIFY ENTITIES OF zdemo_abap_rap_ro_m
    ENTITY root
    CREATE FROM VALUE #(
        %control-key_field = if_abap_behv=>mk-on
        %control-field1 = if_abap_behv=>mk-on
        %control-field2 = if_abap_behv=>mk-on
        %control-field3 = if_abap_behv=>mk-on
        %control-field4 = if_abap_behv=>mk-on
        ( %cid = 'cid5'
          key_field = 5
          field1    = 'iii'
          field2    = 'jjj'
          field3    = 50
          field4    = 51 ) )
    UPDATE FIELDS ( field1 field3 field4 )
        WITH VALUE #( ( %cid_ref = 'cid5'
                        field1   = 'up_kkk'
                        field2   = 'up_lll' "Value not considered
                        field3   = 500
                        field4   = 501 ) )
    MAPPED FINAL(mapped)
    FAILED FINAL(failed)
    REPORTED FINAL(reported).

%key, %tky

  • Both are component groups summarizing all primary keys of a RAP BO instance.
  • Where possible, it is recommended that you use %tky instead of %key. %tky includes %key and also the draft indicator %is_draft. When using %tky in non-draft scenarios, you are prepared for a potential, later switch to a draft scenario. In doing so, you can avoid lots of adaptations in your code by manually adding the indicator.

The code snippet visualizes various specification options regarding %key and %tky as component groups, emphasizing how contained components may be accessed and that these component groups can contain further component groups.

MODIFY ENTITY zdemo_abap_rap_ro_m
      CREATE FROM VALUE #(
         %control = VALUE #( key_field = if_abap_behv=>mk-on
                             field1 = if_abap_behv=>mk-on
                             field2 = if_abap_behv=>mk-on
                             field3 = if_abap_behv=>mk-on
                             field4 = if_abap_behv=>mk-on )
        ( %cid = 'cid1' %key-key_field = 1
          field1 = 'aaa' field2 = 'bbb' field3 = 10 field4 = 11 )
        ( %cid = 'cid2' %key = VALUE #( key_field = 2 )
          field1 = 'ccc' field2 = 'ddd' field3 = 20 field4 = 21 )
        ( %cid = 'cid3' key_field = 3
          field1 = 'eee' field2 = 'fff' field3 = 30 field4 = 31 )
        ( %cid = 'cid4' %data-%key-key_field = 4
          field1 = 'ggg' field2 = 'hhh' field3 = 40 field4 = 41 )
        ( %cid = 'cid5' %data-key_field = 5
          field1 = 'iii' field2 = 'jjj' field3 = 50 field4 = 51 ) )
      "Other options for referring to the key besides using %key
      "are demonstrated.
      UPDATE FIELDS ( field2 ) WITH VALUE #(
        ( %key-key_field = 1 field2 = 'up1' )
        ( key_field = 2 field2 = 'up2' )
        ( %tky-%key-key_field = 3 field2 = 'up3' )
        ( %tky-key_field = 4 field2 = 'up4' )
        ( %tky-%pky-%key-key_field = 5 field2 = 'up5' )
        ( %tky-%pky-key_field = 6 field2 = 'up6' )
        ( %pky-key_field = 7 field2 = 'up7' )
        ( %pky-%key-key_field = 8 field2 = 'up8' )
        ( %data-%key-key_field = 9 field2 = 'up9' )
        ( %data-key_field = 10 field2 = 'up10' ) )
       MAPPED FINAL(mapped)
       FAILED FINAL(failed)
       REPORTED FINAL(reported).

%control

  • Structured component that is a component of many BDEF derived types. It contains the names of all key and data fields of a RAP BO instance, which indicate flags.
  • For example, it is used to get information on which fields are provided or set a flag for which fields are requested by RAP BO providers or RAP BO consumers respectively during the current EML request.
  • For this purpose, the value of each field in the %control structure is of type ABP_BEHV_FLAG. For the value setting, you can use the structured constant mk of interface IF_ABAP_BEHV. Note that the technical type is x length 1.
  • Example: If you want to read data from a RAP BO instance and particular non-key fields in %control are set to if_abap_behv=>mk-off, the values of these fields are not returned in the result.
MODIFY ENTITY zdemo_abap_rap_ro_m 
  CREATE FROM VALUE #(  %control-key_field = if_abap_behv=>mk-on 
                        %control-field1 = if_abap_behv=>mk-on 
                        %control-field2 = if_abap_behv=>mk-on 
                        %control-field3 = if_abap_behv=>mk-on 
                        %control-field4 = if_abap_behv=>mk-on 
                        ( %cid = 'cid1' 
                          key_field = 1 
                          field1 = 'aaa' 
                          field2 = 'bbb' 
                          field3 = 10 
                          field4 = 11 ) 
                        ( %cid = 'cid2' 
                          key_field = 2 
                          field1 = 'ccc' 
                          field2 = 'ddd' 
                          field3 = 20 
                          field4 = 21 ) ) 
      MAPPED FINAL(mapped) 
      FAILED FINAL(failed) 
      REPORTED FINAL(reported). 

%is_draft

  • Represents the draft indicator
  • Used in RAP draft handling and indicates whether a RAP BO instance is active or not. A RAP BO instance with the draft indicator set to true represents a RAP draft instance, e.g. created by a create operation. A commit triggers the saving of the instance to a draft table.
  • Is contained in %tky
  • Is of type ABP_BEHV_FLAG
MODIFY ENTITY zdemo_abap_rap_draft_m
    CREATE AUTO FILL CID
    FIELDS ( num1 arithm_op num2 )
    WITH VALUE #( ( %is_draft = if_abap_behv=>mk-on
                    num1 = 1 arithm_op = '+' num2 = 2 )
                  ( %is_draft = if_abap_behv=>mk-on
                    num1 = 2 arithm_op = '*' num2 = 4 )
                  ( %is_draft = if_abap_behv=>mk-on
                    num1 = 3 arithm_op = '-' num2 = 5 )
                  ( %is_draft = if_abap_behv=>mk-on
                    num1 = 1 arithm_op = '/' num2 = 4 )
                  ( %is_draft = if_abap_behv=>mk-on
                    num1 = 2 arithm_op = 'P' num2 = 5 ) )
    FAILED FINAL(f)
    REPORTED FINAL(r)
    MAPPED FINAL(m).

%target

  • Used to address compositions such as child entities in create operations.
  • Includes the target's primary key and data fields.
MODIFY ENTITIES OF zdemo_abap_rap_ro_m
    ENTITY root
    CREATE FIELDS ( key_field field1 field2 field3 field4 )
    WITH VALUE #( ( %cid      = 'cid_cba'
                    key_field = 9
                    field1    = 'qqq'
                    field2    = 'rrr'
                    field3    = 90
                    field4    = 91 ) )
    CREATE BY \_child
    FIELDS ( key_ch field_ch1 field_ch2 ) WITH VALUE #(      
      ( %cid_ref = 'cid_cba'
        %target = VALUE #( ( %cid      = 'cid_ch1'
                             key_ch    = 9
                             field_ch1 = 'aaa_ch'
                             field_ch2 = 99 )
                           ( %cid      = 'cid_ch2'
                             key_ch    = 10
                             field_ch1 = 'bbb_ch'
                             field_ch2 =  100 ) ) ) )
      MAPPED FINAL(mapped)
      FAILED FINAL(failed)
      REPORTED FINAL(reported).  

The following code snippet illustrates the importance of careful component access and value assignment with component groups in BDEF derived types:

DATA cr_tab TYPE TABLE FOR CREATE zdemo_abap_rap_ro_m.
cr_tab = VALUE #( ( key_field = 1 ) ).

DATA(a) = cr_tab[ 1 ]-key_field.
DATA(b) = cr_tab[ 1 ]-%key-key_field.
DATA(c) = cr_tab[ 1 ]-%data-key_field.
DATA(d) = cr_tab[ 1 ]-%data-%key-key_field.

"Even more specification options with another BDEF derived type.
"This is only to visualize the variety of component groups in BDEF 
"derived types.
DATA upd_tab TYPE TABLE FOR UPDATE zdemo_abap_rap_ro_m.
upd_tab = VALUE #( ( key_field = 1 ) ).

DATA(e) = upd_tab[ 1 ]-key_field.
DATA(f) = upd_tab[ 1 ]-%key-key_field.
DATA(g) = upd_tab[ 1 ]-%tky-%key-key_field.
DATA(h) = upd_tab[ 1 ]-%tky-key_field.
DATA(i) = upd_tab[ 1 ]-%tky-%pky-%key-key_field.
DATA(j) = upd_tab[ 1 ]-%tky-%pky-key_field.
DATA(k) = upd_tab[ 1 ]-%pky-key_field.
DATA(l) = upd_tab[ 1 ]-%pky-%key-key_field.
DATA(m) = upd_tab[ 1 ]-%data-%key-key_field.
DATA(o) = upd_tab[ 1 ]-%data-key_field.

⬆️ back to top

Constants for BDEF Derived Type Components

Several BDEF derived types contain % components, which have a specific type and represent flags. The mentioned %control structure, whose components are of type ABP_BEHV_FLAG, is such a component. When assigning values to these components, ensure you use appropriate values. The IF_ABAP_BEHV interface provides a range of structured constants for this purpose. Although these constants are technically identical, it is recommended that you use them in the right context.

Type Structured Constant Details
ABP_BEHV_FLAG IF_ABAP_BEHV=>MK Marks and unmarks fields in ABAP EML modify and read operations, such as in %control and %element.
ABP_BEHV_FIELD_PERM IF_ABAP_BEHV=>PERM-F Used in the context of field permission results, such as a field marked as mandatory or read-only.
ABP_BEHV_OP_PERM IF_ABAP_BEHV=>PERM-O For operation permission results, such as a delete operation that is marked as enabled.
ABP_BEHV_FIELD_CTRL IF_ABAP_BEHV=>FC-F For field feature control results, such as a field marked with no restrictions.
ABP_BEHV_OP_CTRL IF_ABAP_BEHV=>FC-O For operation feature control results, such as a disabled update operation.
ABP_BEHV_AUTH IF_ABAP_BEHV=>AUTH For authorization results, such as an unauthorized operation.
IF_ABAP_BEHV=>T_CHAR01 IF_ABAP_BEHV=>OP For dynamic ABAP EML statements; e.g. if_abap_behv=>op-m-create for create and if_abap_behv=>op-r-read for read operations.
IF_ABAP_BEHV=>T_CHAR01 IF_ABAP_BEHV=>COP For accumulated change operation information such as in the context of draft additional save; e.g. if_abap_behv=>cop-update for update operations.

⬆️ back to top

Secondary Table Keys of BDEF Derived Types

DATA itab_cr TYPE TABLE FOR CREATE zdemo_abap_rap_ro_m.

itab_cr = VALUE #( %control-key_field = if_abap_behv=>mk-on
                   %control-field1 = if_abap_behv=>mk-on
                   %control-field2 = if_abap_behv=>mk-on
                   %control-field3 = if_abap_behv=>mk-on
                   %control-field4 = if_abap_behv=>mk-on
                   ( %cid           = `cid1`
                     %key-key_field = 1
                     field1         = 'aaa'
                     field2         = 'bbb'
                     field3         = 11
                     field4         = 111 ) ).

"Secondary table keys available in the example table: cid, entity

"The statements demonstrate the secondary table keys using table expressions.
"The statements commented out raise a syntax warning. The secondary table key 
"should be specified explicitly.
"DATA(line_a) = itab_cr[ %cid = `cid1` ].
"DATA(line_b) = itab_cr[ %cid = `cid1` %key = VALUE #( key_field = 1 ) ].
DATA(line_c) = itab_cr[ KEY cid COMPONENTS %cid = `cid1`
                                           %key = VALUE #( key_field = 1 ) ].

"DATA(line_d) = itab_cr[ %key = VALUE #( key_field = 1 ) ].
"The COMPONENTS addition is optional.
DATA(line_e) = itab_cr[ KEY entity %key = VALUE #( key_field = 1 ) ].

⬆️ back to top

Type Mapping for RAP

RAP-Specific Additions to the CORRESPONDING Operator

The CORRESPONDING operator offers RAP-specific additions for handling type mappings related to BDEF derived types and other types. For more information, see the ABAP Keyword Documentation topic.

The following additions are available:

... CORRESPONDING ...( ... MAPPING FROM ENTITY ) ...
... CORRESPONDING ...( ... MAPPING TO ENTITY ) ...
... CORRESPONDING ...( ... USING CONTROL ) ...
... CORRESPONDING ...( ... MAPPING FROM ENTITY USING CONTROL ) ...
... CORRESPONDING ...( ... CHANGING CONTROL ) ...

For some additions, a mapping needs to be specified in the BDEF. For more information, see the
ABAP Keyword Documentation topic.

The following example uses a BDEF derived type from the ABAP cheat sheets. It shows additions that do not require a type mapping to be specified.

"BDEF derived type 
DATA derived_type TYPE STRUCTURE FOR UPDATE zdemo_abap_rap_ro_m.

"Other type
"For simplicity, the structure has the same component names
"and types to avoid further additions in the statement.
DATA: BEGIN OF some_other_type,
		key_field TYPE i,
		field1    TYPE c LENGTH 10,
		field2    TYPE c LENGTH 10,
		field3    TYPE i,
		field4    TYPE i,
		END OF some_other_type.

derived_type = VALUE #( key_field = 1
                        field1 = 'aaa'
                        field2 = 'bbb'
                        field3 = 2
                        field4 = 3
                        %control = VALUE #( key_field = if_abap_behv=>mk-on
                                            field1    = if_abap_behv=>mk-off
                                            field2    = if_abap_behv=>mk-on
                                            field3    = if_abap_behv=>mk-on
                                            field4    = if_abap_behv=>mk-off ) ).

*&---------------------------------------------------------------------*
*& USING CONTROL addition
*&---------------------------------------------------------------------*

"This addition respects the %control component of BDEF derived types, i.e.
"only those fields for which the %control field has been marked as enabled
"are respected by the mapping. A disabled %control field means that the
"mapping is not applied.

"In the example, components are marked as disabled in %control.
"Consequently, the field values are not assigned, and the type-specific
"initial values are used.
some_other_type = CORRESPONDING #( derived_type USING CONTROL ).

*KEY_FIELD    FIELD1     FIELD2    FIELD3    FIELD4
*1                       bbb       2         0

*&---------------------------------------------------------------------*
*& CHANGING CONTROL addition
*&---------------------------------------------------------------------*

"This variant fills the %control structure of a BDEF-derived type based on
"a non-BDEF-derived type that does not include control information.
"In the example, two components are not assigned (i.e. they remain initial).
"Consequently, when using the CORRESPONDING operator with CHANGING CONTROL,
"the %control values are marked as disabled, the others as enabled.

some_other_type = VALUE #( key_field = 4 field1 = 'ccc' field4 = 5 ).

derived_type = CORRESPONDING #( some_other_type CHANGING CONTROL ).

*%CID_REF    KEY_FIELD    FIELD1    FIELD2     FIELD3    FIELD4    %CONTROL
*            4            ccc                  0         5         KEY_FIELD    FIELD1    FIELD2    FIELD3    FIELD4
*                                                                  01           01        00        00        01

ABAP SQL Statements with BDEF Derived Types

The ABAP SQL statements INSERT, UPDATE, MODIFY, and DELETE offer the MAPPING FROM ENTITY addition to handle BDEF derived types.

*&---------------------------------------------------------------------*
*& INSERT
*&---------------------------------------------------------------------*

"Populating a BDEF derived type
DATA cr_der_type TYPE STRUCTURE FOR CREATE zdemo_abap_rap_ro_m.
"%control is not relevant in this example
cr_der_type = VALUE #( key_field = 1
                       field1 = 'aaa'
                       field2 = 'bbb'
                       field3 = 2
                       field4 = 3 ).

INSERT zdemo_abap_rapt1 FROM @cr_der_type MAPPING FROM ENTITY.

*KEY_FIELD    FIELD1    FIELD2    FIELD3    FIELD4
*1            aaa       bbb       2         3

*&---------------------------------------------------------------------*
*& MODIFY
*&---------------------------------------------------------------------*

cr_der_type = VALUE #( BASE cr_der_type
                       field1 = 'YYY'
                       field2 = 'ZZZ' ).

MODIFY zdemo_abap_rapt1 FROM @cr_der_type MAPPING FROM ENTITY.

*KEY_FIELD    FIELD1    FIELD2    FIELD3    FIELD4
*1            YYY       ZZZ       2         3

*&---------------------------------------------------------------------*
*& UPDATE with the INDICATORS SET STRUCTURE %control addition
*&---------------------------------------------------------------------*

"Populating a BDEF derived type
"%control is relevant in this example. Some %control values are enabled,
"some are not.
cr_der_type = VALUE #( key_field = 1
                       field1 = '###'
                       field2 = '...'
                       field3 = 100
                       field4 = 200
                       %control = VALUE #( key_field = if_abap_behv=>mk-on
                                           field1    = if_abap_behv=>mk-on
                                           field2    = if_abap_behv=>mk-off
                                           field3    = if_abap_behv=>mk-off
                                           field4    = if_abap_behv=>mk-on ) ).

UPDATE zdemo_abap_rapt1 FROM @cr_der_type
	INDICATORS SET STRUCTURE %control MAPPING FROM ENTITY.

*KEY_FIELD    FIELD1    FIELD2    FIELD3    FIELD4
*1            ###       ZZZ       2         200

*&---------------------------------------------------------------------*
*& DELETE
*&---------------------------------------------------------------------*

DELETE zdemo_abap_rapt1 FROM @cr_der_type MAPPING FROM ENTITY.

[!NOTE]
More information and ABAP statements: Type Mapping for RAP

⬆️ back to top

ABAP EML Syntax

The focus is here on selected EML statements. These statements can be fairly long and various additions are possible. Find more information on the EML statements here.

ABAP EML Syntax for Modifying Operations

The modifying operations covered include the standard operations (using the additions CREATE, CREATE BY, UPDATE, and DELETE) and non-standard operations (actions) using the addition EXECUTE. All EML statements for the mentioned operations begin with MODIFY. The following commented code snippets demonstrate the short and long form of EML MODIFY statements.

[!NOTE] Unlike reading operations, modifying operations are not enabled by default. You must make the respective notations in the BDEF:

...
create;
update;
delete;
action some_act;
...

⬆️ back to top

Create Operation Using the Short Form of ABAP EML MODIFY Statements

"Declaration of data objects using BDEF derived types

DATA: cr_tab        TYPE TABLE FOR CREATE root_ent,    "input derived type
      mapped_resp   TYPE RESPONSE FOR MAPPED root_ent, "response parameters
      failed_resp   TYPE RESPONSE FOR FAILED root_ent,
      reported_resp TYPE RESPONSE FOR REPORTED root_ent.

"Input derived type for the EML statement is filled using the VALUE operator
"Assumption: key_field is the key field having type i,
"field1 and field2 are data fields with character-like data type.
"Specify %cid even if not used or of interest; it must be unique within a request

cr_tab = VALUE #(
        ( %cid   = 'cid1' key_field = 1
          field1 = 'A'    field2    = 'B' )
        ( %cid = 'cid2'
          "Just to demo %data/%key. You can specify fields with or without
          "the derived type components
          %data = VALUE #( %key-key_field = 2
                          field1         = 'C'
                          field2         = 'D' ) ) ).

"EML statement, short form
"root_ent must be the full name of the root entity, it is basically the name of the BDEF

MODIFY ENTITY root_ent
  CREATE "determines the kind of operation
  FIELDS ( key_field field1 field2 ) WITH cr_tab   "Fields to be respected for the
                                                   "input derived type and the input
                                                   "derived type itself
  MAPPED mapped_resp          "mapping information
  FAILED failed_resp          "information on failures with instances
  REPORTED reported_resp.     "messages

⬆️ back to top

[!NOTE]

⬆️ back to top

Create Operation Using the Long Form of ABAP EML MODIFY Statements

MODIFY ENTITIES OF root_ent      "full name of root entity
  ENTITY root                    "root or child entity (alias name if available)
  CREATE FROM                    "FROM as further field selection variant
  VALUE #( ( %cid      = 'cid'   "Input derived type created inline
             key_field = 3
             field1    = 'E'
             field2    = 'F'
             %control = VALUE #(                "Must be filled when using FROM
               key_field = if_abap_behv=>mk-on
               field1    = if_abap_behv=>mk-on
               field2    = if_abap_behv=>mk-on ) ) )
  MAPPED DATA(m)       "Target variables declared inline
  FAILED DATA(f)
  REPORTED DATA(r).

"Note: You can use the AUTO FILL CID addition to fill %cid automatically. It is 
"also possible in the short form. 
MODIFY ENTITIES OF root_ent      
  ENTITY root                    
  CREATE AUTO FILL CID WITH 
  VALUE #( ( key_field = 3
             field1    = 'E'
             field2    = 'F'
             %control = VALUE #(                
               key_field = if_abap_behv=>mk-on
               field1    = if_abap_behv=>mk-on
               field2    = if_abap_behv=>mk-on ) ) )
  MAPPED DATA(m2)       
  FAILED DATA(f2)
  REPORTED DATA(r2).

[!NOTE]

⬆️ back to top

Update Operations

*&---------------------------------------------------------------------*
*& Short form of EML MODIFY statement
*&---------------------------------------------------------------------*

"The example code snippet uses data objects declared upfront instead of
"inline declarations.

DATA: upd_tab       TYPE TABLE FOR UPDATE zdemo_abap_rap_ro_m,
      failed_resp   TYPE RESPONSE FOR FAILED zdemo_abap_rap_ro_m,
      reported_resp TYPE RESPONSE FOR REPORTED zdemo_abap_rap_ro_m.

"Note:
"The BDEF derived type does not have a %cid component but %cid_ref
"to refer to an existing instance (its %cid value) within the same
"EML request. The example includes the reference to an existing
"instance using %cid_ref for demonstration purposes, commented out.
"The example does not include an actually referable instance. When 
"there is no referable instance, a runtime error occurs.

upd_tab = VALUE #(
        ( key_field = 1 field1 = 'A' field2 = 'B' field3 = 1 field4 = 2 )
        ( key_field = 2 field1 = 'C' field2 = 'D' field3 = 3 field4 = 4 )
        "( %cid_ref = `some_cid` field1 = 'E' field2 = 'F' field3 = 5 field4 = 6 )
        ).

"Note:
"- The statement includes the field specification option FIELDS ( ... ) WITH.
"  The fields to be respected are included in the parentheses. For these,
"  %control is flagged as if_abap_behv=>mk-on. The others, field3 and field4,
"  are not specified. Therefore, %control is flagged as if_abap_behv=>mk-off
"  for these fields.
"- Typically, the key fields are not included since changing them is ruled
"  out in the example's BDEF: field ( readonly:update ) key_field;
"- The EML statement does not have the mapped response parameter. No
"  new instance are created in update operations.

MODIFY ENTITY zdemo_abap_rap_ro_m
  UPDATE
  FIELDS ( field1 field2 ) WITH upd_tab
  FAILED failed_resp
  REPORTED reported_resp.

*&---------------------------------------------------------------------*
*& Long form of EML MODIFY statement
*&---------------------------------------------------------------------*

"Note:
"- The statement's operands are all declared inline.
"- The statement includes the field specification option FROM.
"- This specification option requires %control to be filled explicitly.
"  Unlike the previous example, the update operation also respects
"  field3 and field4, indicated by flagging all non-key components with
"  if_abap_behv=>mk-on. As above, changing the key values is ruled out.
"  Flagging key_field with if_abap_behv=>mk-on results in a runtime error.
"- See the excursion with specifying the %control component values.
"  Applying the coding technique mentioned there (providing the corresponding
"  values for all table lines outside of the inner parentheses), you can
"  save the specification of code lines.
"- As above, an example with %cid_ref is included but commented out since
"  the example does not inlcude a referable instance.

MODIFY ENTITIES OF zdemo_abap_rap_ro_m
  ENTITY root
  UPDATE
  FROM VALUE #(
    ( key_field = 4 field1 = 'G' field2 = 'H' field3 = 7 field4 = 8
      %control = VALUE #( key_field = if_abap_behv=>mk-off
                          field1 = if_abap_behv=>mk-off
                          field2 = if_abap_behv=>mk-on
                          field3 = if_abap_behv=>mk-on
                          field4 = if_abap_behv=>mk-on ) )
    ( key_field = 5 field1 = 'I' field2 = 'J' field3 = 9 field4 = 10
      %control = VALUE #( key_field = if_abap_behv=>mk-off
                          field1 = if_abap_behv=>mk-on
                          field2 = if_abap_behv=>mk-on
                          field3 = if_abap_behv=>mk-on
                          field4 = if_abap_behv=>mk-on ) )
*    ( %cid_ref = `another_cid` field1 = 'K' field2 = 'L' field3 = 11 field4 = 12
*      %control = VALUE #( key_field = if_abap_behv=>mk-off
*                          field1 = if_abap_behv=>mk-on
*                          field2 = if_abap_behv=>mk-on
*                          field3 = if_abap_behv=>mk-on
*                          field4 = if_abap_behv=>mk-on ) )
     )
  FAILED DATA(f_resp)
  REPORTED DATA(r_resp).

⬆️ back to top

Delete Operations

*&---------------------------------------------------------------------*
*& Short form of EML MODIFY statement
*&---------------------------------------------------------------------*

"The example code snippet uses data objects declared upfront instead of
"inline declarations.

DATA: del_tab           TYPE TABLE FOR DELETE zdemo_abap_rap_ro_m,
      failed_response   TYPE RESPONSE FOR FAILED zdemo_abap_rap_ro_m,
      reported_response TYPE RESPONSE FOR REPORTED zdemo_abap_rap_ro_m.

"Note:
"The BDEF derived type only includes components to identify instances.
"This can be either referring to an existing existing using %cid_ref
"- its %cid value - within the same EML request, or the key. The example
"includes the reference to an existing instance using %cid_ref for
"demonstration purposes, commented out. The example does not include an
"actually referable instance. When there is no referable instance, a
"runtime error occurs.

del_tab = VALUE #(
    ( key_field = 1 )
    ( key_field = 2 )
    "( %cid_ref = `some_cid` )
    ).

"Note:
"EML MODIFY staments for delete operations can only use the field
"specification option FROM.

MODIFY ENTITY zdemo_abap_rap_ro_m
  DELETE
  FROM del_tab
  FAILED failed_response
  REPORTED reported_response.

*&---------------------------------------------------------------------*
*& Long form of EML MODIFY statement
*&---------------------------------------------------------------------*

"Note:
"The statement's operands are all declared inline.

MODIFY ENTITIES OF zdemo_abap_rap_ro_m
  ENTITY root
  DELETE
  FROM VALUE #(
    ( key_field = 4 )
    ( key_field = 5 )
    "( %cid_ref = `another_cid` )
    )
  FAILED DATA(f_del_resp)
  REPORTED DATA(r_del_resp).

⬆️ back to top

Dynamic Form of ABAP EML MODIFY Statements

DATA: op_tab           TYPE abp_behv_changes_tab,
        create_root_tab  TYPE TABLE FOR CREATE zdemo_abap_rap_ro_m,
        update_root_tab  TYPE TABLE FOR UPDATE zdemo_abap_rap_ro_m,
        delete_root_tab  TYPE TABLE FOR UPDATE zdemo_abap_rap_ro_m,
        cba              TYPE TABLE FOR CREATE zdemo_abap_rap_ro_m\_child,
        update_child_tab TYPE TABLE FOR UPDATE zdemo_abap_rap_ch_m,
        delete_child_tab TYPE TABLE FOR DELETE zdemo_abap_rap_ch_m.

create_root_tab = VALUE #(
            ( %cid = 'cid1'
                key_field = 5
                %control-key_field = if_abap_behv=>mk-on
                field1 = 'a'
                %control-field1 = if_abap_behv=>mk-on
                field2 = 'b'
                %control-field2 = if_abap_behv=>mk-on )
            ( %cid = 'cid2'
                key_field = 6
                %control-key_field = if_abap_behv=>mk-on
                field1 = 'd'
                %control-field1 = if_abap_behv=>mk-on
                field2 = 'd'
                %control-field2 = if_abap_behv=>mk-on )
            ( %cid = 'cid3'
                key_field = 7
                %control-key_field = if_abap_behv=>mk-on
                field1 = 'e'
                %control-field1 = if_abap_behv=>mk-on
                field2 = 'f'
                %control-field2 = if_abap_behv=>mk-on ) ).

update_root_tab = VALUE #(
            ( %cid_ref = 'cid2'
            field1 = 'g'
            %control-field1 = if_abap_behv=>mk-on
            field2 = 'h'
            %control-field2 = if_abap_behv=>mk-on ) ).

cba = VALUE #(
            ( %cid_ref = 'cid1'
                %target = VALUE #( (
                %cid = 'cid_cba1'
                key_ch = 10
                %control-key_ch = if_abap_behv=>mk-on
                field_ch1 = 'i'
                %control-field_ch1 = if_abap_behv=>mk-on
                field_ch2 = 1
                %control-field_ch2 = if_abap_behv=>mk-on
            ) ) )
            ( %cid_ref = 'cid2'
                %target = VALUE #( (
                %cid = 'cid_cba2'
                key_ch = 20
                %control-key_ch = if_abap_behv=>mk-on
                field_ch1 = 'j'
                %control-field_ch1 = if_abap_behv=>mk-on
                field_ch2 = 2
                %control-field_ch2 = if_abap_behv=>mk-on
            ) ) )
            ( %cid_ref = 'cid3'
                %target = VALUE #( (
                %cid = 'cid_cba3'
                key_ch = 30
                %control-key_ch = if_abap_behv=>mk-on
                field_ch1 = 'k'
                %control-field_ch1 = if_abap_behv=>mk-on
                field_ch2 = 3
                %control-field_ch2 = if_abap_behv=>mk-on
            ) ) ) ).

update_child_tab = VALUE #(
            ( key_field = 6
                field_ch1 = 'l'
                %control-field_ch1 = if_abap_behv=>mk-on
                field_ch2 = 4
                %control-field_ch2 = if_abap_behv=>mk-on ) ).

delete_root_tab = VALUE #( ( key_field = 7 ) ).

delete_child_tab = VALUE #( ( key_field = 7 ) ).

op_tab = VALUE #(
        ( op = if_abap_behv=>op-m-create
            entity_name = 'ZDEMO_ABAP_RAP_RO_M'
            instances   = REF #( create_root_tab ) )
        ( op = if_abap_behv=>op-m-update
            entity_name = 'ZDEMO_ABAP_RAP_RO_M'
            instances   = REF #( update_root_tab ) )
        ( op = if_abap_behv=>op-m-delete
            entity_name = 'ZDEMO_ABAP_RAP_RO_M'
            instances   = REF #( delete_root_tab ) )
        ( op = if_abap_behv=>op-m-create_ba
            entity_name = 'ZDEMO_ABAP_RAP_RO_M'
            sub_name    = '_CHILD'
            instances   = REF #( cba ) )
        ( op = if_abap_behv=>op-m-update
            entity_name = 'ZDEMO_ABAP_RAP_CH_M'
            instances   = REF #( update_child_tab ) )
        ( op = if_abap_behv=>op-m-delete
            entity_name = 'ZDEMO_ABAP_RAP_CH_M'
            instances   = REF #( delete_child_tab ) )
        ).

MODIFY ENTITIES OPERATIONS op_tab
    MAPPED   DATA(m)
    FAILED   DATA(f)
    REPORTED DATA(r).

⬆️ back to top

Executing Actions

"Example snippet taken from the executable example
"The long form of the MODIFY statement is used. It includes
"a create operation and executes an action. 
MODIFY ENTITIES OF zdemo_abap_rap_ro_m
    ENTITY root
    CREATE FIELDS ( key_field field1 field2 field3 field4 )
        WITH VALUE #(
        ( %cid = 'cid_x2'
          key_field = 7
          field1    = 'ooo'
          field2    = 'ppp'
          field3    = 70
          field4    = 71 ) )
    EXECUTE multiply_by_2 FROM VALUE #(
        "Executing action via %cid_ref
        ( %cid_ref = 'cid_x2' )
        "Executing action via key
        ( key_field  =  1  )
        ( key_field  =  2  ) ) 
    MAPPED DATA(mapped)
    FAILED DATA(failed)
    REPORTED DATA(reported).

⬆️ back to top

Excursions

Specifying %control Component Values in the Short Form of VALUE Constructor Expressions
MODIFY ENTITIES OF zdemo_abap_rap_ro_m
    ENTITY root
    CREATE FROM VALUE #(
        %control-key_field = if_abap_behv=>mk-on
        %control-field1    = if_abap_behv=>mk-on
        %control-field2    = if_abap_behv=>mk-on
        %control-field3    = if_abap_behv=>mk-on
        %control-field4    = if_abap_behv=>mk-off
        ( %cid      = 'cid1'
          key_field = 1
          field1    = 'aaa'
          field2    = 'bbb'
          field3    = 10
          field4    = 100 )
        ( %cid      = 'cid2'
          key_field = 2
          field1    = 'ccc'
          field2    = 'ddd'
          field3    = 20
          field4    = 200 ) )
    MAPPED DATA(m)
    FAILED DATA(f)
    REPORTED DATA(r).

⬆️ back to top

Combining Multiple Operations in One ABAP EML Request

The following EML statement combines multiple operations in one EML request. It demonstrates the use of the BDEF derived type components %cid and %cid_ref.

MODIFY ENTITIES OF root_ent
  ENTITY root
  CREATE FIELDS ( key_field field1 field2 ) WITH
    VALUE #( ( %cid    = 'cid4' key_field = 4
                field1 = 'G'    field2    = 'H' )
              ( %cid   = 'cid5' key_field = 5
                field1 = 'I'    field2    = 'J' ) )

  UPDATE FIELDS ( field2 ) WITH
    VALUE #( ( %cid_ref = 'cid4' field2 = 'Z' ) )

  DELETE FROM
    VALUE #( ( %cid_ref  = 'cid5' ) "Instance referenced via %cid_ref
             ( key_field = 9 ) )    "Instance referenced via the key
...

⬆️ back to top

Creating Instances for the Root and Child Entity (Deep Create)

The following code snippet shows a deep create.

MODIFY ENTITIES OF root_ent
  ENTITY root_ent
  CREATE FIELDS ( key_field field1 field2 ) WITH
    VALUE #( ( %cid = 'cid6' key_field = 6
                field1 = 'I' field2 = 'J' ) )
  CREATE BY \_child
  FIELDS ( key_field_child field1_child field2_child  ) WITH
    VALUE #( ( %cid_ref = 'cid6'
                %target = VALUE #( ( %cid            = 'cid_child_1'
                                     key_field_child = 1
                                     field1_child    = 'aa'
                                     field2_child    = 'bb' )
                                   ( %cid            = 'cid_child_2'
                                     key_field_child = 2
                                     field1_child    = 'cc'
                                     field2_child    = 'dd' ) ) ) )
...

⬆️ back to top

ABAP EML Syntax for Reading Operations

⬆️ back to top

Reading Operations

READ ENTITIES OF root_ent
  ENTITY root_ent
  ALL FIELDS WITH
  VALUE #( ( key_field = 1 )   "Derived type TYPE TABLE FOR READ IMPORT only includes the keys
           ( key_field = 2 ) )
  RESULT DATA(result)
  FAILED DATA(f)
  REPORTED DATA(r).

⬆️ back to top

Read-by-Association Operations

"Read-by association operation: parent to child
READ ENTITIES OF root_ent
  ENTITY root_ent
  BY \_child
  ALL FIELDS WITH VALUE #( ( key_field = 1 ) )
  RESULT DATA(rba_res1)
  LINK DATA(links1).
  ...

"Read-by association operation: child to parent
READ ENTITIES OF root_ent
  ENTITY child_ent
  BY \_parent
  ALL FIELDS WITH VALUE #( ( key_field = 1 key_field_child = 1 ) )
  RESULT DATA(rba_res2)
  LINK DATA(links2).
  ...

⬆️ back to top

Dynamic ABAP EML READ Statements

In addition to the short and long forms described above, various ABAP EML statements also have dynamic forms. Taking EML read operations as an example, the following code snippet shows a dynamic EML READ ENTITIES statement. The relevant syntax element is the OPERATIONS addition. The dynamic form allows the collection of read operations for multiple RAP BOs in one EML statement. For more information, see the ABAP keyword documentation and the comments in the snippet.

"The statement is taken from the executable example. The example has a 
"root entity and a child entity. For both entities, RAP BO instances
"are to be read (read and read-by-association operation).

DATA:
    "The following data object is the operand of the dynamic EML statement
    "It is an internal table and has a special, RAP-specific type.
    op_tab          TYPE abp_behv_retrievals_tab,

    "More data object declarations (internal tables typed with BDEF
    "derived types) that are relevant for the EML statement.
    "For both entities (root and child), RAP BO instances are to be 
    "read. The internal tables are used for components of the internal
    "table op_tab further down.
    read_dyn        TYPE TABLE FOR READ IMPORT zdemo_abap_rap_ro_m,
    read_dyn_result TYPE TABLE FOR READ RESULT zdemo_abap_rap_ro_m,
    rba_dyn         TYPE TABLE FOR READ IMPORT zdemo_abap_rap_ro_m\_child,
    rba_dyn_result  TYPE TABLE FOR READ RESULT zdemo_abap_rap_ro_m\_child,
    rba_dyn_link    TYPE TABLE FOR READ LINK zdemo_abap_rap_ro_m\_child.

"Filling the internal tables, i.e. which instances are to be read
"Root entity
"Example:
"- The key is comprised of the field 'key_field'. It is of type i.
"- The %control structure is filled, flagging those fields that
"  are to be read. Flagging the key field is not required.
read_dyn = VALUE #(
    ( %key-key_field = 1
      %control = VALUE #(
        field1 = if_abap_behv=>mk-on
        field2 = if_abap_behv=>mk-on
        field3 = if_abap_behv=>mk-on
        field4 = if_abap_behv=>mk-on ) )
    ( %key-key_field = 2
      %control = VALUE #(
        field1 = if_abap_behv=>mk-on
        field2 = if_abap_behv=>mk-on
        field3 = if_abap_behv=>mk-on
        field4 = if_abap_behv=>mk-on ) ) ).

"Child entity
"Instances to be read for a read-by-association operation
"The shared key is 'key_field'.
rba_dyn = VALUE #(
    ( %key-key_field = 1
      %control = VALUE #(
        key_ch    = if_abap_behv=>mk-on        
        field_ch1 = if_abap_behv=>mk-on
        field_ch2 = if_abap_behv=>mk-on ) )
    ( %key-key_field = 2
      %control = VALUE #(
        key_ch    = if_abap_behv=>mk-on
        field_ch1 = if_abap_behv=>mk-on
        field_ch2 = if_abap_behv=>mk-on ) ) ).

"Filling the internal table that is the operand of the
"dynamic EML statement
"This table has optional and mandatory components.
op_tab = VALUE #(
    ( "op: Specifies the operation to be executed; is mandatory;
        "    can be set with the predefined constants, e.g. OP-R-READ
        "    etc., of interface IF_ABAP_BEHV
        op = if_abap_behv=>op-r-read
        "entity_name: Specifies the name of the RAP BO entity for which
        "             the operation is executed; is mandatory
        entity_name = 'ZDEMO_ABAP_RAP_RO_M'
        "instances: Specifies a reference to an internal table holding
        "           the input keys; must be appropriately typed; is mandatory
        instances   = REF #( read_dyn )
        "results: Specifies a reference to an internal table with the required
        "         BDEF derived type for the read results; is mandatory
        results     = REF #( read_dyn_result ) )
    ( op = if_abap_behv=>op-r-read_ba
        entity_name = 'ZDEMO_ABAP_RAP_RO_M'
        "sub_name: Only relevant for specifying association names in
        "          read-by-association operations; in that context, it is mandatory
        sub_name    = '_CHILD'
        "full: Optional flag; specifies if all target instances are to be retrieved
        full        = abap_true
        instances   = REF #( rba_dyn )
        results     = REF #( rba_dyn_result )
        "links: Reference to internal table holding the key pairs of the source and
        "       target
        links       = REF #( rba_dyn_link ) ) ).

READ ENTITIES OPERATIONS op_tab.

⬆️ back to top

Accessing Change Information

Example statements

"Short form
DATA read_changes TYPE TABLE FOR READ CHANGES demo_rap_entity. 
 
READ ENTITY IN LOCAL MODE demo_rap_entity 
  WITH CHANGES 
  ALL FIELDS WITH CORRESPONDING #( keys ) 
  RESULT read_changes 
  FAILED failed.

"Dynamic form
DATA: op_tab          TYPE abp_behv_retrievals_tab, 
      read_dyn        TYPE TABLE FOR READ IMPORT demo_rap_entity, 
      read_dyn_result TYPE TABLE FOR READ CHANGES demo_rap_entity, 
      entity          TYPE abp_entity_name VALUE 'DEMO_RAP_ENTITY'. 
 
read_dyn = VALUE #( FOR wa IN keys ( 
  %key-key_field  = wa-key_field 
  %control-field1 = if_abap_behv=>mk-on 
  %control-field2 = if_abap_behv=>mk-on 
  %control-field3 = if_abap_behv=>mk-on 
  %control-field4 = if_abap_behv=>mk-on ) ). 
 
op_tab = VALUE #( ( 
  op          = if_abap_behv=>op-r-read 
  entity_name = entity 
  full        = if_abap_behv=>typekind-result_chg 
  instances   = REF #( read_dyn ) 
  results     = REF #( read_dyn_result ) ) ). 
 
READ ENTITIES IN LOCAL MODE OPERATIONS op_tab FAILED DATA(f).

⬆️ back to top

COMMIT ENTITIES: Persisting to the Database

Variant/Addition Notes

Short form of COMMIT ENTITIES

The following snippet shows a create operation. This operation has only an impact on the database with the COMMIT ENTITIES statement. Triggering the save sequence means that the execution of the statement triggers the calling of the saver methods available in the saver class of a behavior implementation. In managed scenarios (except for some special variants), the saving is done automatically without implementing a dedicated saver method. Optionally, you can specify the RESPONSES addition followed by a data object of type ABP_BEHV_RESPONSE_TAB to retrieve information returned by the response parameters of RAP saver methods.


MODIFY ENTITIES OF root_ent
  ENTITY root_ent
  CREATE FIELDS ( key_field field1 field2 ) WITH
  VALUE #( ( %cid = 'cid' key_field = 7
             field1 = 'K' field2 = 'L' ) )
  MAPPED DATA(mapped)
  FAILED DATA(failed)
  REPORTED DATA(rep).

COMMIT ENTITIES.

IF sy-subrc <> 0.
  ...
ENDIF.

... "Some modifications

DATA f_resp TYPE abp_behv_response_tab.
DATA r_resp TYPE abp_behv_response_tab.
"Note: Inline declarations for the data objects are also possible.
COMMIT ENTITIES RESPONSES FAILED f_resp REPORTED r_resp.

IF sy-subrc <> 0.
  ...
ENDIF.

Long form of COMMIT ENTITIES

The long syntax form includes the retrieval of information for one or more RAP BO entities. Root entities must be specified.


COMMIT ENTITIES
 RESPONSE OF zdemo_abap_rap_ro_m
   FAILED   DATA(f1)
   REPORTED DATA(r1)
 RESPONSE OF zdemo_abap_rap_draft_m
   FAILED   DATA(f2)
   REPORTED DATA(r2).

IF sy-subrc <> 0.
    ...
ENDIF.

Dynamic form of COMMIT ENTITIES

The dynamic syntax form allows you to retrieve RAP responses from RAP saver methods by dynamically specifying one or more RAP BO root entities.


DATA: root_name1  TYPE abp_root_entity_name VALUE 'ZDEMO_ABAP_RAP_RO_M',
      root_name2  TYPE abp_root_entity_name VALUE 'ZDEMO_ABAP_RAP_DRAFT_M',
      failed_resp TYPE abp_behv_response_tab.

DATA(dyn_tab) = VALUE abp_entity_name_tab( ( root_name1 )
                                           ( root_name2 ) ).

COMMIT ENTITIES  RESPONSES OF dyn_tab
    FAILED   failed_resp
    REPORTED DATA(reported_resp).

IF sy-subrc <> 0.
    ...
ENDIF.

Specifying a commit scope

  • Especially used in late numbering scenarios to get the final keys from the preliminary keys (using the CONVERT KEY addition)
  • The commit scope is opened by COMMIT ENTITIES BEGIN ... (... stands for further syntax options such as the specification of RESPONSES ... or RESPONSE OF ... ), and closed by COMMIT ENTITIES END..

COMMIT ENTITIES BEGIN. 
 
... 

"CONVERT KEY OF some_bo FROM ...-%pid TO DATA(some_key).

"For example, converting the preliminary keys (e.g. %pid components) 
"based on entries in the MAPPED table of a RAP BO entity. 
"Using a CONVERT KEY statement, you can retrieve the final keys of
"individual instances, and store them in a local variable. 
 
COMMIT ENTITIES END.

Simulating a commit

  • The optional IN SIMULATION MODE addition can be specified with COMMIT ENTITIES statements allowing a RAP transaction to be checked.
  • With this addition, only the RAP early save phase is processed without saving data, i.e. a final COMMIT WORK is not performed.
  • The addition can be used to check the consistency of the transaction by evaluating, for example, the sy-subrc value as a result of executing the commit in simulation mode.

DELETE FROM zdemo_abap_rapt1.

DO 2 TIMES.
 MODIFY ENTITIES OF zdemo_abap_rap_ro_m
  ENTITY root
  CREATE FIELDS ( key_field )
  AUTO FILL CID WITH VALUE #( ( key_field = 100 ) )
  MAPPED DATA(m1)
  FAILED DATA(f1)
  REPORTED DATA(r1).

 IF sy-index = 1.
   COMMIT ENTITIES IN SIMULATION MODE.
 ELSE.
   COMMIT ENTITIES.
 ENDIF.

 IF sy-subrc <> 0.
  ...
 ENDIF.

 SELECT FROM zdemo_abap_rapt1
  FIELDS key_field
  ORDER BY key_field
  INTO TABLE @DATA(tab).

 IF sy-index = 1.
  ASSERT tab IS INITIAL.
  "Clearing the transactional buffer
  ROLLBACK ENTITIES.
 ELSE.
  ASSERT lines( tab ) = 1.
  ASSERT tab[ 1 ]-key_field = 100.
 ENDIF.
ENDDO.

⬆️ back to top

ROLLBACK ENTITIES

The following example demonstrates the effect of ROLLBACK ENTITIES. In the second loop pass, ROLLBACK ENTITIES clears the transactional buffer, leaving nothing to commit. Therefore, the assertions are also true for the second loop.

DELETE FROM zdemo_abap_rapt1.

DO 2 TIMES.
 MODIFY ENTITIES OF zdemo_abap_rap_ro_m
  ENTITY root
  CREATE FIELDS ( key_field )
  AUTO FILL CID WITH VALUE #( ( key_field = sy-index ) )
  MAPPED DATA(m1)
  FAILED DATA(f1)
  REPORTED DATA(r1).

 IF sy-index = 2.
   ROLLBACK ENTITIES.
 ENDIF.

COMMIT ENTITIES.

 IF sy-subrc <> 0.
  ...
 ENDIF.

 SELECT FROM zdemo_abap_rapt1
  FIELDS key_field
  ORDER BY key_field
  INTO TABLE @DATA(tab).

  ASSERT lines( tab ) = 1.
  ASSERT tab[ 1 ]-key_field = 1.
ENDDO.

⬆️ back to top

GET PERMISSIONS: Retrieving Information about RAP BO Permissions

DATA request TYPE STRUCTURE FOR PERMISSIONS REQUEST zdemo_abap_rap_ro_m.

request = VALUE #(
    %create          = if_abap_behv=>mk-on
    %update          = if_abap_behv=>mk-on
    %delete          = if_abap_behv=>mk-on
    %field-key_field = if_abap_behv=>mk-on
    %field-field1    = if_abap_behv=>mk-on
    %field-field2    = if_abap_behv=>mk-on
    %field-field3    = if_abap_behv=>mk-on
    %field-field4    = if_abap_behv=>mk-on ).

GET PERMISSIONS ONLY GLOBAL ENTITY zdemo_abap_rap_ro_m
    REQUEST request
    RESULT DATA(result)
    FAILED DATA(failed)
    REPORTED DATA(reported).

⬆️ back to top

SET LOCKS: Exclusively Locking Instances

Example code snippet illustrating all forms:

DATA key_tab TYPE TABLE FOR KEY OF zdemo_abap_rap_ro_u.
key_tab = VALUE #( ( key_field = 1 )
                   ( key_field = 2 ) ).

"Short form
SET LOCKS ENTITY zdemo_abap_rap_ro_u
    FROM key_tab
    FAILED DATA(f_short).

"Long form
"The statements specifies the key table inline.
SET LOCKS OF zdemo_abap_rap_ro_u
    ENTITY root FROM VALUE #( ( key_field = 1 ) )
    ENTITY child FROM VALUE #( ( key_field = 2 ) )
    FAILED   DATA(f_long)
    REPORTED DATA(r_long).

"Dynamic form
DATA root_keys TYPE TABLE FOR KEY OF zdemo_abap_rap_ro_u.
DATA child_keys TYPE TABLE FOR KEY OF zdemo_abap_rap_ch_u.

root_keys  = VALUE #( ( key_field = 1 ) ).
child_keys = VALUE #( ( key_field = 2 )
                      ( key_field = 3 ) ).

"Populating the lock table that is of type abp_behv_locks_tab
"Components:
"- entity_name: Name of RAP BO entity in capital letters
"- instances: Reference to an internal table typed with the derived type TYPE TABLE FOR KEY OF
DATA(locks_tab) = VALUE abp_behv_locks_tab(
  ( entity_name = 'ZDEMO_ABAP_RAP_RO_U' instances = REF #( root_keys ) )
  ( entity_name = 'ZDEMO_ABAP_RAP_CH_U' instances = REF #( child_keys ) ) ).

SET LOCKS locks_tab FAILED   DATA(f_dyn)
                    REPORTED DATA(r_dyn).

The code in the collapsible section illustrates the effect of a SET LOCKS statement using artifacts from the ABAP cheat sheet repository.

🟢 Click to expand for example code
CLASS zcl_class1 DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.
    INTERFACES if_oo_adt_classrun.
  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.

CLASS zcl_class1 IMPLEMENTATION.
  METHOD if_oo_adt_classrun~main.

    DELETE FROM zdemo_abap_rapt1.
    MODIFY zdemo_abap_rapt1 FROM TABLE @( VALUE #( ( key_field = 1 )
                                                   ( key_field = 2 )
                                                   ( key_field = 3 )
                                                   ( key_field = 4 ) ) ).

    DATA key_tab  TYPE TABLE FOR KEY OF zdemo_abap_rap_ro_u.
    key_tab = VALUE #(
              ( key_field = 1 )
              ( key_field = 2 ) ).

    SET LOCKS ENTITY zdemo_abap_rap_ro_u
        FROM key_tab
        FAILED   DATA(f)
        REPORTED DATA(r).

    ASSERT 1 = 1.

  ENDMETHOD.
ENDCLASS.
CLASS zcl_class2 DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.
    INTERFACES if_oo_adt_classrun.
  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.


CLASS zcl_class2 IMPLEMENTATION.
  METHOD if_oo_adt_classrun~main.

    DATA key_tab TYPE TABLE FOR KEY OF zdemo_abap_rap_ro_u.
    key_tab = VALUE #( ( key_field = 1 )
                       ( key_field = 2 )
                       ( key_field = 3 )
                       ( key_field = 4 ) ).

    DATA enq TYPE string_table.
    TRY.
        DATA(lo_lock) = cl_abap_lock_object_factory=>get_instance( iv_name = 'EZDEMO_ABAP_LOCK' ).

        LOOP AT key_tab REFERENCE INTO DATA(lr_key).
          APPEND |key_field = { lr_key->key_field }| TO enq.
          TRY.
              lo_lock->enqueue( it_parameter = VALUE #(
                ( name = 'KEY_FIELD' value = REF #( lr_key->key_field ) ) ) ).
              APPEND |  - Enqueue ok| TO enq.
            CATCH cx_abap_foreign_lock INTO DATA(err_foreign_lock).
              APPEND |  - { err_foreign_lock->get_text( ) }| TO enq.
            CATCH cx_abap_lock_failure INTO DATA(err_lock_failure).
              APPEND |  - { err_lock_failure->get_text( ) }| TO enq.
          ENDTRY.
        ENDLOOP.
      CATCH cx_abap_lock_failure INTO err_lock_failure.
        APPEND err_lock_failure->get_text( ) TO enq.
    ENDTRY.

    out->write( enq ).

    SET LOCKS ENTITY zdemo_abap_rap_ro_u
        FROM key_tab
        FAILED DATA(f).

    out->write( f ).

  ENDMETHOD.
ENDCLASS.

⬆️ back to top

Raising RAP Business Events

*&---------------------------------------------------------------------*
*& Syntax for the declaration part of a global RAP event handler class
*&---------------------------------------------------------------------*

CLASS cl_event_handler DEFINITION PUBLIC FOR EVENTS OF some_bdef.
  ...
ENDCLASS.

*&---------------------------------------------------------------------*
*& Syntax for the declaration part of a local event handler class
*& in the CCIMP include of a RAP event handler class 
*&---------------------------------------------------------------------*

CLASS lhe_event DEFINITION INHERITING FROM cl_abap_behavior_event_handler.
  ...
ENDCLASS.

*&---------------------------------------------------------------------*
*& RAP event handler method definition
*&---------------------------------------------------------------------*

"Notes: 
"- Must be defined as instance methods in the private visibility section. 
"- The input parameter par is an internal table of type TYPE TABLE FOR EVENT.
"- This type includes the keys of RAP BO instances (and %param, if the event
"  is specified with a parameter in the BDEF)
"- The methods do not contain RAP response parameters.
METHODS meth FOR ENTITY EVENT par FOR some_bdef~some_evt.

*&---------------------------------------------------------------------*
*& RAISE ENTITY EVENT statement in an ABP, e.g. the save_modified method
*& in managed scenarios with additional save
*&---------------------------------------------------------------------*

...
CLASS lsc IMPLEMENTATION.
  METHOD save_modified.
   "Assumption: An event is specified for create operations in the BDEF as follows
   "event created;
   IF create-some_bdef IS NOT INITIAL.    
     RAISE ENTITY EVENT some_bdef~created 
        FROM VALUE #( FOR <cr> IN create-root ( %key = VALUE #( some_key = <cr>-some_key ) ) ).
   ENDIF.

   "Assumption: An event is specified for delete operations in the BDEF as follows
   "event deleted parameter some_abstract_entity;
   "The abstract entity has two parameters, for example, with which additional
   "information can be passed.
   IF delete-some_bdef IS NOT INITIAL.
     RAISE ENTITY EVENT some_bdef~deleted
       FROM VALUE #( FOR <del> IN delete-some_bdef (
         %key   = VALUE #( some_key = <del>-some_key )
         %param = VALUE #( par_a = '01'
                           par_b = 'Item deleted' ) ) ).
   ENDIF.
  ENDMETHOD.
ENDCLASS.

⬆️ back to top

Additions to ABAP EML Statements in ABAP Behavior Pools

There are a special additions when using EML in behavior pools.

IN LOCAL MODE Addition

Syntax:

MODIFY ENTITIES OF root_ent IN LOCAL MODE
  ENTITY root
  EXECUTE book
  FROM action_tab
  ...

⬆️ back to top

AUGMENTING Addition to ABAP EML MODIFY Statements

MODIFY AUGMENTING ENTITY some_bdef
    UPDATE FROM ...

"relates_tab is of type abp_behv_relating_tab
MODIFY AUGMENTING ENTITY some_bdef
    UPDATE FROM ... RELATING TO some_instances BY relates_tab.

⬆️ back to top

RAP Excursions

Using Keys and Identifying RAP BO Instances in a Nutshell

The following bullet points outline important aspects regarding keys and identifying RAP BO instances in ABAP EML statements.

Why is it important?

How can a RAP BO instance be uniquely identified?

General rule: A RAP BO instance must - where available - always be uniquely identifiable by its transactional key (%tky) for internal processing during the RAP interaction phase. %tky always contains all relevant components for the chosen scenario.

Assignment of Key Component Groups

⬆️ back to top

RAP Concepts

RAP numbering

Draft

⬆️ back to top

Late Numbering and Key Identification in the Late Phase of the RAP Save Sequence

⬆️ back to top

Ensuring Data Consistency in a RAP Transaction

The LUW concept, which deals with the transfer of data from one consistent state to another, applies to applications using RAP. RAP transactions are integrated with the SAP LUW, which is a prerequisite for transactional consistency. RAP provides a standardized approach and rules (RAP BO contract) for the RAP business object (BO) runtime to ensure that the RAP transaction is correctly implemented, data inconsistencies are avoided, and the SAP LUW is successfully completed.

⬆️ back to top

Phases of a RAP Transaction

A RAP transaction is divided into two phases during the runtime of a RAP BO, while the second phase can be divided into two subphases that serve different purposes.

Phases of a RAP Transaction

RAP interaction phase:

RAP save sequence:

(Optional:) Saver methods called in the RAP early save phase:

  1. finalize: For final calculations and data changes before saving. In managed scenarios, determinations specified with ON SAVE are called when reaching this method.

  2. check_before_save: For data consistency checks in the transactional buffer. In managed scenarios, validations specified with ON SAVE are called when this method is reached.

  3. cleanup_finalize: If there are failures in at least one of the previous saver methods, further processing with the RAP late save phase is rejected and the transaction returns to the interaction phase. Before that, this saver method is called, allowing changes made in the finalize method to be rolled back.

If there are errors in the early save phase, sy-subrc returns the value 4 after COMMIT ENTITIES statements. If the data in the transactional buffer is consistent after the early save phase, the late save phase is processed, which also means that a point of no return has been reached. Unlike the early save phase, you cannot return to the interaction phase when you reach the late save phase. Either the RAP transaction ends with a successful commit, or the changes are rolled back and a runtime error occurs.

Saver methods called in the RAP late save phase:

  1. adjust_numbers: Provides RAP BO instances with their final numbers. This method is available only in late numbering scenarios.
  2. save (or save_modified in managed scenarios with an unmanaged or additional save): Used to save data from the transactional buffer to the database. If there are no issues, the final database commit is triggered and an implicit COMMIT WORK is executed.

cleanup method: After a successful save, the cleanup method clears the transactional buffer. It completes the save sequence.

⬆️ back to top

Commit and Rollback in a RAP Transaction

The default ABAP statements for RAP are COMMIT ENTITIES (triggers the RAP save sequence and the final database commit; in natively supported RAP scenarios, the commit is performed implicitly and automatically by the RAP runtime engine) and ROLLBACK ENTITIES (rolls back all changes of the current RAP transaction, i.e. the transactional buffer is cleared by calling the cleanup method). Both are RAP-specific and end the RAP transaction.

Notes on COMMIT ... and ROLLBACK ... statements due to the integration of RAP transactions into the SAP LUW:

[!NOTE] Special Case: Failures in the Late Save Phase

⬆️ back to top

Allowed/Forbidden Operations in a Behavior Implementation in a RAP Transaction

The following restrictions apply to operations and/or statements in the individual phases of a RAP transaction in ABAP behavior implementations. Note that, depending on setting the strict mode in the BDEF, runtime errors may occur due to the use of forbidden statements, or static code checks may be applied. Note that most operations/statements refer to the use in the unrestricted ABAP language scope.

Operations/Statements Interaction phase Early save phase Late save phase Notes
Database commits using secondary connections

(unrestricted ABAP language scope)
X X X Secondary connections are allowed for infrastructure purposes, for example. They can be used to store data that is not part of the main transaction, such as application logs, traces, or number ranges.
Database commits using the standard connection

(unrestricted ABAP language scope)
X X - Database commits can be made in phases other than the late phase, for example, by calling external services or using a WAIT statement.
sRFC (CALL FUNCTION ... DESTINATION), aRFC (CALL FUNCTION ... STARTING NEW TASK)

(unrestricted ABAP language scope)
X X - Allowed in phases other than the late save phase, e.g. for the purpose of parallelization within the application. It is up to the application to ensure consistency, e.g. to ensure read-only access, to handle a potential two-phase commit, or to provide a proper error handling.
Database modifications - - X Only allowed in the late save phase because the data being processed is always potentially inconsistent. Database changes in other phases would result in multiple database transactions instead of one transaction, which would disrupt the SAP LUW.
Update function module (CALL FUNCTION ... IN UPDATE TASK)

(unrestricted ABAP language scope)
- - X Can be used to ensure that there is only one database transaction. In addition, registering function modules for update tasks at stages other than the late save phase would interfere with RAP draft scenarios, for example, where data is stored in draft tables. There is no way to unregister function modules once they have been registered.
bgRFC (CALL FUNCTION ... IN BACKGROUND UNIT)

(unrestricted ABAP language scope)
- - X
tRFC, qRFC (CALL FUNCTION ... IN BACKGROUND TASK)

(unrestricted ABAP language scope)
- - - Obsolete technologies.
PERFORM ON COMMIT, PERFORM ON ROLLBACK

(unrestricted ABAP language scope)
(X) (X) X Basically possible in all phases, but should be reserved for the late save. Note: The use of these statements indicates improper integration with RAP. It is especially important to check draft scenarios when calling legacy code and using these statements. Instead, ABAP EML or procedure calls that do not include a COMMIT WORK should be used.
Transaction control COMMIT WORK, ROLLBACK WORK X/- X/- X/- When a transactional phase has been explicitly set by methods of the CL_ABAP_TX class (find more information here), the transaction owner is allowed to execute a commit or rollback statement. In the contexts of RAP (that is, where RAP is the transaction owner, for example, in handler and saver methods), local consumption of RAP business events, bgPF, and classified APIs, commit or rollback statements are not allowed.
Dynpro processing (e.g. SET SCREEN, CALL SCREEN, LEAVE SCREEN, CALL DIALOG, SUPPRESS DIALOG, MESSAGE without INTO, WRITE, STOP)

(unrestricted ABAP language scope)
- - - Not allowed in ABAP behavior implementations. Results in a runtime error.
Transaction processing (CALL TRANSACTION, LEAVE TRANSACTION)

(unrestricted ABAP language scope)
- - - Not allowed to prevent (unwanted) integration of other LUWs.
Raising an exception (RAISE EXCEPTION) - - - It is not allowed to leave a RAP transaction this way.
Raising a RAP business event using RAISE ENTITY EVENT - - X The statements are recommended in the save and save_modified RAP saver methods.
Report processing (SUBMIT ...)

(unrestricted ABAP language scope)
- - - Not allowed in transactional contexts. Results in a syntax or runtime error.
SUBMIT ... AND RETURN does not currently return an error, but it leads to potentially unwanted screen processing, and because of the missing return channel, there is no proper error handling.

⬆️ back to top

RAP Additional and Unmanaged Save

⬆️ back to top

Handling Dependencies on RAP Business Objects in ABAP Unit

The ABAP Unit Tests cheat sheet includes an example demonstrating the handling of dependencies on RAP business objects:

Note that there is a RAP-specific variant of the CREATE OBJECT statement available. CREATE OBJECT ... FOR TESTING. enables the instantiation of RAP handler classes. Find more information in the Development guide for the ABAP RESTful Application Programming Model.

⬆️ back to top

Several RAP-related system classes and functionality are available, including (some of them are mentioned in the cheat sheet):

⬆️ back to top

More Information

⬆️ back to top

Executable Examples

main Branch

This cheat sheet is supported by different executable examples demonstrating various scenarios:

[!NOTE]

⬆️ back to top

rap Branch

The ABAP cheat sheets GitHub repository features simplified, non-semantic demo RAP BOs in the rap branch for exploring various RAP-related features, syntax, and concepts in simple contexts. Topics include managed and unmanaged RAP BOs, draft-enabled RAP BOs, numbering concepts like early and late numbering, field-specific characteristics, standard operations (CRUD), actions as non-standard operations, authorizations, local RAP business events, and more.

Unlike the examples included in the main branch - they primarily focus on ABAP EML and include ABAP classes as RAP BO consumers - the example RAP BOs in the rap branch are set up to be explored using preview SAP Fiori UIs.

For more detailed information and semantic RAP examples, refer to the Development guide for the ABAP RESTful Application Programming Model and the ABAP Flight Reference Scenario for the ABAP RESTful Application Programming Model.

⬆️ back to top