RAP - EML (Part 2)
Controlling complex RAP entities with the Entity Manipulation Language is what this article is about and how you work with deep nodes.
Table of contents
We laid the foundations for the Entity Manipulation Language, EML for short, in a first article a while ago. There we showed you what EML is and how you can use it with RAP objects. In this article, we'll look at the same thing for complex entities.
Introduction
In last week's article we built a complex data model together and looked at the differences to a simple entity. The model does not only consist of a single table, but several tables depict an object, as is the standard in the "normal" world.
EML forms the basis for accessing RAP objects without going through the OData service, but as a quick way to access the object's functions in the current system. The functions are strongly encapsulated within an object and are therefore easily maintainable and reusable.
The IDE (Eclipse) also supports the development of the statements and makes suitable suggestions when accessing the entities:
Read
In the first step, we read both dependent entities with an EML statement. To do this, we define a filter, which can come from outside later or be set up in other ways. To do this, we select two receipts from the database, the receipt numbers can differ from your receipts:
DATA lt_filter TYPE STANDARD TABLE OF ZBS_R_RAPCInvoice WITH EMPTY KEY.
lt_filter = VALUE #( ( Document = '30000000' )
( Document = '30000005' ) ).
Now we build up the corresponding reading statement, for better readability we have prepared it once so that we can describe the individual steps:
READ ENTITIES OF ZBS_R_RAPCInvoice
ENTITY Invoice
ALL FIELDS WITH CORRESPONDING #( lt_filter )
RESULT DATA(lt_invoice)
ENTITY Invoice BY \_Position
FIELDS ( Document PositionNumber Material ) WITH CORRESPONDING #( lt_filter )
RESULT DATA(lt_position)
FAILED FINAL(ls_failed).
First of all we address the RAP object from which we want to read the information. Then we specify the first entity from which we want to read the data. The schema follows the standard, after the entity comes the constraint of the fields, then the key and finally we assign the result to a variable. In the second section we repeat this behavior, this time for better illustration we have delimited the fields in order not to read all contents from the database. We pass the filter back and can assign the result. Finally, we take over the failed accesses. The structure contains information if certain accesses did not work.
The result from the tables now looks like this:
Insert
In the second step, we want to insert new data and create invoices and the appropriate items in one go. To do this, we prepare the data that we want to insert in the next step:
DATA lt_new_invoice TYPE TABLE FOR CREATE ZBS_R_RAPCInvoice.
DATA lt_new_position TYPE TABLE FOR CREATE ZBS_R_RAPCInvoice\_Position.
lt_new_invoice = VALUE #( ( %cid = 'B1'
Document = '40000000'
Partner = '1000000004'
%control = VALUE #( Document = if_abap_behv=>mk-on Partner = if_abap_behv=>mk-on ) ) ).
lt_new_position = VALUE #(
( %cid_ref = 'B1'
%target = VALUE #(
( %cid = 'P1'
PositionNumber = 1
Material = 'R0001'
%control = VALUE #( PositionNumber = if_abap_behv=>mk-on Material = if_abap_behv=>mk-on ) )
( %cid = 'P2'
PositionNumber = 2
Price = '2.20'
Currency = 'EUR'
%control = VALUE #( PositionNumber = if_abap_behv=>mk-on Price = if_abap_behv=>mk-on Currency = if_abap_behv=>mk-on ) ) ) ) ).
When structuring the data, it is important to use the correct reference (%CID), because this is how the invoice is linked to the item. We then attach our data to the position under %TARGET. The positions are given their own IDs. When preparing the data, it is important to fill the %CONTROL structure, since this is the only way to fill the fields when they are inserted. There is a special feature when creating the data types for the main entity and the appropriate dependent entity. Calling up the system then looks like this:
MODIFY ENTITIES OF ZBS_R_RAPCInvoice
ENTITY Invoice
CREATE FROM lt_new_invoice
ENTITY Invoice
CREATE BY \_Position FROM lt_new_position
FAILED DATA(ls_failed).
COMMIT ENTITIES.
Calling MODIFY to initiate the changing action. Then the first entity is given (invoices) and in the next step the items, but make sure that the system is created via the association. It is also possible to create positions directly, but the key (document number) would have to be known for this. In the last step, we accept the structure in order to be able to react to errors. Don't forget to set a COMMIT afterwards so that the data is written to the database.
We can use the data preview to look at the new data records, here is an excerpt from the item table with the two items created in the invoice:
Delete
Before we can delete the record, we should first define which keys we want to delete. For this we use a dummy table as a filter for the data records.
DATA lt_filter TYPE STANDARD TABLE OF ZBS_R_RAPCInvoice WITH EMPTY KEY.
lt_filter = VALUE #( ( Document = '40000000' ) ).
In the next step we give the key to the MODIFY. Here it is sufficient to delete the document, all dependent entities are taken into account and also deleted from the database.
MODIFY ENTITIES OF ZBS_R_RAPCInvoice
ENTITY Invoice
DELETE FROM CORRESPONDING #( lt_filter )
FAILED DATA(ls_failed).
COMMIT ENTITIES.
The statement to delete is very short and yet very practical. RAP takes care of the dependent entities that come down the line, so we don't have to worry about deleting them.
Full example
At the end again the complete example of the shown demos. For formatting we use the ABAP Cleaner, a handy tool to keep source code clean:
CLASS zcl_bs_demo_crap_eml DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PRIVATE SECTION.
METHODS read_data
IMPORTING io_out TYPE REF TO if_oo_adt_classrun_out.
METHODS insert_data
IMPORTING io_out TYPE REF TO if_oo_adt_classrun_out.
METHODS delete_data
IMPORTING io_out TYPE REF TO if_oo_adt_classrun_out.
ENDCLASS.
CLASS zcl_bs_demo_crap_eml IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
read_data( out ).
insert_data( out ).
delete_data( out ).
ENDMETHOD.
METHOD read_data.
DATA lt_filter TYPE STANDARD TABLE OF ZBS_R_RAPCInvoice WITH EMPTY KEY.
lt_filter = VALUE #( ( Document = '30000000' )
( Document = '30000005' ) ).
READ ENTITIES OF ZBS_R_RAPCInvoice
ENTITY Invoice
ALL FIELDS WITH CORRESPONDING #( lt_filter )
RESULT DATA(lt_invoice)
ENTITY Invoice BY \_Position
FIELDS ( Document PositionNumber Material ) WITH CORRESPONDING #( lt_filter )
RESULT DATA(lt_position)
FAILED FINAL(ls_failed).
IF ls_failed-invoice IS NOT INITIAL.
io_out->write( `Failed!` ).
ENDIF.
io_out->write( `Invoices:` ).
io_out->write( lt_invoice ).
io_out->write( `Positions:` ).
io_out->write( lt_position ).
ENDMETHOD.
METHOD insert_data.
DATA lt_new_invoice TYPE TABLE FOR CREATE ZBS_R_RAPCInvoice.
DATA lt_new_position TYPE TABLE FOR CREATE ZBS_R_RAPCInvoice\_Position.
lt_new_invoice = VALUE #( ( %cid = 'B1'
Document = '40000000'
Partner = '1000000004'
%control = VALUE #( Document = if_abap_behv=>mk-on Partner = if_abap_behv=>mk-on ) ) ).
lt_new_position = VALUE #(
( %cid_ref = 'B1'
%target = VALUE #(
( %cid = 'P1'
PositionNumber = 1
Material = 'R0001'
%control = VALUE #( PositionNumber = if_abap_behv=>mk-on Material = if_abap_behv=>mk-on ) )
( %cid = 'P2'
PositionNumber = 2
Price = '2.20'
Currency = 'EUR'
%control = VALUE #( PositionNumber = if_abap_behv=>mk-on Price = if_abap_behv=>mk-on Currency = if_abap_behv=>mk-on ) ) ) ) ).
MODIFY ENTITIES OF ZBS_R_RAPCInvoice
ENTITY Invoice
CREATE FROM lt_new_invoice
ENTITY Invoice
CREATE BY \_Position FROM lt_new_position
FAILED DATA(ls_failed).
COMMIT ENTITIES.
IF ls_failed-invoice IS NOT INITIAL.
io_out->write( `Failed!` ).
ELSE.
io_out->write( `Creation OK` ).
ENDIF.
ENDMETHOD.
METHOD delete_data.
DATA lt_filter TYPE STANDARD TABLE OF ZBS_R_RAPCInvoice WITH EMPTY KEY.
lt_filter = VALUE #( ( Document = '40000000' ) ).
MODIFY ENTITIES OF ZBS_R_RAPCInvoice
ENTITY Invoice
DELETE FROM CORRESPONDING #( lt_filter )
FAILED DATA(ls_failed).
COMMIT ENTITIES.
IF ls_failed-invoice IS NOT INITIAL.
io_out->write( `Failed!` ).
ELSE.
io_out->write( `Deletion OK` ).
ENDIF.
ENDMETHOD.
ENDCLASS.
Conclusion
Working with EML should be easier for you after our article and even with complex and larger RAP objects you don't have to be afraid of not being able to trade them anymore. There are a few things to consider when working with multiple entities.