Technical Articles
SADL – Handling OData Navigation Without Association
Overview
In this blog post I’ll share how I was able to enable navigation between two OData entities that did not have an association mapped by SADL. I wasted a lot of time searching for a blog post or question on this and didn’t find one. So now that I figured out the answer hopefully it will save you time! Also I hope to learn from feedback and comments, so feel free to do so.
Related Topics
I’ll be discussing several frameworks today, here are some helpful links for more about those topics.
Business Object Process Framework (BOPF)
SADL
Context
Our development environment contains the following SAP Versions
- EHP7 For SAP ERP 6.0 SP17
- SAP Netweaver 7.4 SP20
- SAP Fiori Front-End Server 4.0
I’m developing a Fiori Elements List Report application that manages material demand records. The end users also want to see related material master data for each demand record.
The OData entity for demand data is a BOPF object. The related material master data is supported by a CDS View. Both entities were imported and are supported by SADL.
Relevant Demand attributes
- Demand Number (Key)
- Material Number (ZzMatnrExt)
Material Master Attributes
- Material Number (Matnr)
- Material Type (Mtart)
- Material Group (Matkl)
- Base Unit (Meins)
Problem
I have not found a way to associate a BOPF object to a related dataset supported by a CDS view. So, how can two entities that are related to each other but don’t have an association supported by SADL navigate between their respective OData entities?
Well after lots and lots of google searching I finally came across the link I shared above titled Fine-Tuning the Execution of SADL-Based Gateway Services. This document from SAP shares some extra SADL capabilities you can enable through a little extra ABAP work. The specific entry in that site I used was Handling OData Navigation.
Implementation
Create an association in your OData Service between the two entities.
-
- Right click on the Data Model Folder
- Name your association, provide the entities and cardinality, create a navigation property.
- In step 2 the referential constraints are provided.
- This requires you to specify only the key from the principal entity. This is usually a problem when I link to related data. The values that link the two entities may not be key values on either entity.
- So, I provide no referential constraint in this step as they will be specified in the later step where we define the condition to select target entity records from the database.
- Use the delete row button to remove the referential constraint.
- In Step 3 the entity set and association set are named.
- Right click on the Data Model Folder
You should now see the association and navigation info created in your odata service project.
Create class instance attributes to store the navigation information.
-
- The first step specified by the Handling OData Navigation document is to add two attributes.
- Go to your DPC_EXT class of your odata service.
- Go to the Attributes tab, add the two attributes specified by the documentation.
- The first step specified by the Handling OData Navigation document is to add two attributes.
In the getter methods of the target entity, store the navigation information.
-
- The second step specified by the Handling OData Navigation document is to store the navigation information in the getter methods of the target entity.
- Our target entity is MATNR_INFO, we’ll redefine the methods and add the code to store the navigation information in the class member attributes.
- Select the MATNR_INFOSET_GET_ENTITYSET method, push the Redefine Method button.
- Add the code from the Handling Odata Navigation step 2. Also you’ll notice that there is commented out code that calls SUPER->MATNR_INFOSET_GET_ENTITYSET. Uncomment this code and pass the parameters from our redefined method to it. This allows the normal SADL processing to continue for requests.
- Repeat this process for the MATNR_INFOSET_GET_ENTITY method as well.
Force SADL to ignore the navigation and define a condition to select the target entities from the database.
-
- The third and final step from the Handling OData Navigation document is to intercept the navigation to the target entity MATNR_INFO and define the conditions by which to select the related data.
- Redefine the IF_SADL_GW_QUERY_CONTROL~SET_QUERY_OPTIONS method in your DPC_EXT class following the same principal steps depicted above.
- Following the code example from the Handling OData Navigation document, set up a case statement.
- Follow the code comments to help understand the process. I did add another method to my DPC_EXT class to read the Demand record from the database by the key, as the entire record is not passed in to the DPC_EXT class during navigation.
-
CASE iv_entity_set. WHEN 'MATNR_INFOSet'. IF mt_navigation_info IS NOT INITIAL. DATA(ls_nav_step) = mt_navigation_info[ 1 ]. " Is this the navigation we have to handle (BO_DMND -> MATNR_INFO)? IF ls_nav_step-source_entity_type = 'BO_DMND' AND ls_nav_step-nav_prop = 'MATNR_INFO'. " Make SADL ignore navigation io_query_options->remove_navigation_info( ). " Define condition based on source entity key DATA(lo_cond_factory) = cl_sadl_cond_prov_factory_pub=>create_basic_condition_factory( ). "Read ZCOLLECTOR record from DB to get ZZ_MATNR_EXT field. DATA lv_key TYPE /BOBF/CONF_KEY. lv_key = mt_source_keys[ name = 'KEY' ]-value. DATA(ls_collector) = GET_DEMAND_BY_KEY( EXPORTING IV_KEY = lv_key ). * io_query_options->add_condition_provider( * lo_cond_factory->equals( * name = 'ZZ_MATNR_EXT' " ABAP field name of GW property * value = mt_source_keys[ name = 'ZZ_MATNR_EXT' ]-value ) ). " Define condition based on target entity key (if any) IF ls_collector IS NOT INITIAL. DATA lv_matnr_ext TYPE string. lv_matnr_ext = ls_collector-zz_matnr_ext. io_query_options->add_condition_provider( lo_cond_factory->equals( name = 'MATNR' " ABAP field name of GW property value = lv_matnr_ext ) ). ENDIF. ENDIF. ENDIF. ENDCASE. *TRY. CALL METHOD SUPER->IF_SADL_GW_QUERY_CONTROL~SET_QUERY_OPTIONS EXPORTING IV_ENTITY_SET = iv_entity_set IO_QUERY_OPTIONS = io_query_options . * CATCH /IWBEP/CX_MGW_BUSI_EXCEPTION . * CATCH /IWBEP/CX_MGW_TECH_EXCEPTION . *ENDTRY. endmethod.
-
Evaluate the OData service output and follow the navigation to see if the related data is available.
Now when I evaluate the data provided in the odata service I can see the new relationship.
-
- In the metadata
-
- In the OData response to getting a single Demand record, there is a navigation to material info.
-
- If you follow this navigation you’ll see the related material info.
Utilize the data in a Fiori Elements List Report
The entire effort we just went through will now enable us to annotate the target entity to display on our List Report application as we see fit. I enabled it to display as a Quick View Facet.
Conclusion
If you find yourself in the situation where entities don’t have an association supported by SADL, you can enable navigation between SADL supported OData entities by specifying your own conditions to relate the data.
The SADL fine tuning documentation also has many other helpful options that I’ve taken advantage of as well.
Please leave comments if this was helpful or if you have suggestions on changes or options I should also consider.
Nice that you like our SADL fine tuning documentation . I would only like to add that such fine tuning is only available if the mapped data source approach is used. Not if you use the Referenced Datasource apprpoach.
In the future (with upcoming version of SAP S/4HANA) scenarios like this will become easier with the ABAP RESTful Programming Model.
Thanks Andre, I can't wait to get my hands on the newer methodologies!
Then you should try out out new trial offering
https://blogs.sap.com/2019/09/28/its-trialtime-for-abap-in-sap-cloud-platform/
?
hi,
What if we do not map DDIC Table like MARC but a reference custom Structure and then code to populate ET_ENTITYSET via DPC_EXT ? how do you control aggregation using this SADL approach as data is not flowing actually by mapping by database table.
Due to some complication ,we did not use CDS and used ABAP Approach to populate ET_ENTITYSET but now need to to do totaling/ subtotaling and other aggregation option ! can this be done using fine tune ?
Regards,
Rohan
Thanks for sharing, Tim, and happy you got into blogging. I look forward to seeing many more. It is very well explained and with good pictures allows for easy way to follow what you were doing.
Thanks Sergio, I hope to do more with SADL, BOPF and Fiori Elements for sure.
Nice to see you blogging, Tim!
Thanks Lucia, I've gained so much from reading them over the years. Maybe I can help someone else out.
I also forgot to say: Thank you! for this blog that will definitely help others looking how to integrate SADL and non-SADL based entities! ?
Hi Tim,
Much information Blog.
Thanks for sharing!
Thank you,
Syam
Nice blog! I haven't encountered this scenario yet but this blog will definitely be helpful if that happens. Very good explanation.
Hey Tim,
Very nice informative blog!
Thank you,
Pavan Golesar