How to add Multiple Entities (Relationship Data) in one Operation in SAP Netweaver and OData Services?
The context for today’s article: I was working on a Fiori PoC (Proof of Concept) for my client where I had to do an update on one of the entity sets with multiple records in one call (one header and multiple line items). I tried with Create Operation on the entity set with multiple records but somehow when the call is made to the model; I can only see the first record is passed to the model always. Again if we want to create or update one header and multiple items then we then have to call Create/Update Header operation and then followed by the call Create/Update Items Operations in back to back multiple calls to Model. This seemed weird!!
After some research, I found that SAP has given an option to do these kinds of operations in an OData Model. This is called DEEP INSERT.
In this exercise, we will learn how we can define and call a DEEP INSERT operation to do an update for business data where there exist a Parent to Child relationship and we want to create all related data in one go i.e. in one call.
For my scenario, I am trying to allocate multiple components to an ALM Order (SAP transaction IW31/32. Popularly for Work Orders). So, in this case, my header is an Order Operation and items are Components allocated to that Operation.
If you go to transaction IW32/33 and open an existing order and navigate to Operations tab and double click on it, it will take you to the details view of that operation where you can add components.
The objective of this discussion is to how to define an operation in the data model so that we can add multiple rows to an entity without having to call CREATE/UPDATE operations multiple times.
Service Implementation in my PoC
The data model in my case looks like as follows.
The hierarchy that business data in my example model follows is as:
Service Order Operation (SR_ServiceOrder_Operation) -> Navigation : SR_ServiceOrder_ComponentSet (Technical Name : SR_SERVICEORDER_COMPONENTSET) Components (SR_ServiceOrder_Component)
Snapshot from the DATA MODEL for identifying the technical name of the navigation highlighted in green above.
Step 1: Redefine the method
/IWBEP/IF_MGW_APPL_SRV_RUNTIME~CREATE_DEEP_ENTITY in the DPC Extension class in backend OData Service.
First of all, we need to create a structure that represents the exact XML representation of the data what is going to be posted by UI.
In order to know what will be the structure the easy way out is:
Go to the SAP Gateway Client and run a $expand query on Header Entity Set to get the data from the Item by a GET method.
(In the above example, the SR_ServiceOrder_OperationSet entity set is the Header and the SR_ServiceOrder_ComponentSet entity set is the Item. The section which is (Orderid=’4927185′,Activity=’0010′) is the data with the key for header entity set. Hope you all know these by now. Come on, guys!! We are in Part IX.
Now when we want to post data we need to change the URI to point to the Header and call POST method. The revised URI from the UI (frontend) should be as follows to let system call DEEP INSERT method.
Please Note: MODEL identifies to call a CREATE/UPDATE method or a DEEP INSERT method based on the URI. In the URI if MODEL finds the $expand as a parameter then it calls the DEEP INSERT method else normal CREATE/UPDATE operation will be called. So it is very critical for the UI developer to send the URI the in right format.
This query will result into a response. You can use this response as a request and do a POST method. MODEL understands that this POST operation is not a Create (C) or Update (U) post. It will in-turn call the CREATE_DEEP_ENTITY method of the DPC Extension class.
In the class, the importing parameter IO_DATA_PROVIDER is used for getting the XML payload from UI. We need to create a local structure which can hold the data provided by the UI payload.
For my requirement, we have created a structure named ‘zpm_sr_service_order_operation’ which has the following structure.
The highlighted name of the field which will hold more than one entry MUST have the same name as the technical name of the navigation. (Here we are discussing one level relationship data. In case we need multi-level relationship data then also need to follow the same approach).
Write the Logic inside the Method: /IWBEP/IF_MGW_APPL_SRV_RUNTIME~CREATE_DEEP_ENTITY
DATA: BEGIN OF lw_data. INCLUDE TYPE zpm_sr_service_order_operation. DATA: END OF lw_data.
Please Note: In the above definition the Include type zpm_sr_service_order_operation is the entity type of the Operation (Header) and zpm_sr_service_order_comp_tt is a table type of entity type components (Items). The name of the field which would hold the ITEM data (components in our example) should have the same name as the name of the Navigation i.e. SR_ServiceOrder_ComponentSet.
TRY. io_data_provider->read_entry_data( IMPORTING es_data = lw_data ). CATCH /iwbep/cx_mgw_tech_exception. " ENDTRY.
The above code will read the XML payload from UI and do the transformation and fill the local structure lw_data. The lw_data is the deep structure as we have already defined. Going into the deep structure we can call our own custom FM/BAPI to Create or Post data in SAP.
Once the BAPI/custom FM does the data posting we need to fill the right response data in the exporting parameter ER_DEEP_ENTITY. The exporting parameter ER_DEEP_ENTITY will have the same structure as the local variable IW_DATA. We just need to call the standard method ‘COPY_DATA_TO_REF’ available in the extension class as :
copy_data_to_ref( EXPORTING is_data = lw_data CHANGING cr_data = er_deep_entity ).
Please Note : The method which we are re-implementing is a generic method and is used for all kinds of DEEP INSERT on different entity sets on that service. So we need to write our code within a proper check on IV_ENTITY_SET_NAME. In my case the IV_ENTITY_SET_NAME would the ‘SR_ServiceOrder_OperationSet’, so all my logic should be within the check for this entity set.
Another important thing is about the exception handling in this method. The Method gives two exceptions /IWBEP/CX_MGW_BUSI_EXCEPTION & /IWBEP/CX_MGW_TECH_EXCEPTION for reporting any error to the user on UI. Depending on whether it is a business/technical exception use the proper exception class.
In my case, since my API can return failure messages based on some validations built within it , I have handled it as :
DATA: ls_t100key TYPE scx_t100key. ls_t100key-msgid = ls_return-id. ls_t100key-msgno = ls_return-number. ls_t100key-attr1 = ls_return-message. *ls_return is the BAPI return structure RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception EXPORTING textid = ls_t100key.
Step 2: UI development from SAPUI5 Perspective
Gather all input data which are required to form data then format data according to entity set and navigation as per cardinality maintained in service. If it mismatches XML will not able to parse. There isn’t any limitation mentioned by SAP for Deep Entity Create set. Here we tried with 4 level Deep Entity creation.
Data need to be formed in format of parent child relationship like shown below:
CreateData: Root Element(1:1)
requestChildSO: Child of CreateData(1:1)
operationChild: Child of requestChildSO(1:n)
child: Child of operationChild(1:n)
It can go to nth level deep. So, there is no limitation. CreateData will parse as XML similarly XML input required in service for creation.
Call Model for the creation of Data, here EntitySet is root Parent Entity set.