Skip to Content
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.

    1. Right click on the Data Model Folder
    2. Name your association, provide the entities and cardinality, create a navigation property.
    3. In step 2 the referential constraints are provided.
      1. 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.
      2. 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.
      3. Use the delete row button to remove the referential constraint.
    4. In Step 3 the entity set and association set are named.

You should now see the association and navigation info created in your odata service project.

Create class instance attributes to store the navigation information.

    1. The first step specified by the Handling OData Navigation document is to add two attributes.
    2. Go to your DPC_EXT class of your odata service.
    3. Go to the Attributes tab, add the two attributes specified by the documentation.

In the getter methods of the target entity, store the navigation information.

    1. The second step specified by the Handling OData Navigation document is to store the navigation information in the getter methods of the target entity.
    2. 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.
    3. Select the MATNR_INFOSET_GET_ENTITYSET method, push the Redefine Method button.
    4. 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.
    5. 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.

    1. 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.
    2. Redefine the IF_SADL_GW_QUERY_CONTROL~SET_QUERY_OPTIONS method in your DPC_EXT class following the same principal steps depicted above.
    3. Following the code example from the Handling OData Navigation document, set up a case statement.
    4. 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.
      1.   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.

11 Comments
You must be Logged on to comment or reply to a post.