This is a test message to test the length of the message box.
Login
ABAP RAP Custom Entity
Created by Software-Heroes

RAP - Custom Entity Value Help (Deep Dive)

2055

With the Custom Entity you have the most freedom in RAP when developing ABAP Cloud applications, but what about potential errors?



In this article we want to implement a value help with a custom entity. We will go through the different pitfalls step by step and what you should pay attention to during development.

 

Introduction 

We have already described the custom entity in an older article and explained how it works. The custom entity provides a structure and implements the logic via an ABAP class. The entity itself does not contain any data, but must always be called by the SADL framework first. This is why custom entities are mainly used in RAP applications.

In this example, we want to extend our simple RAP application to include a search function for cities and will go through everything step by step again.

 

Installation

In the first step, we begin by creating the Core Data Service and the ABAP class.

 

Class

Since the class in the annotation is also checked when the custom entity is created, we implement the empty class first. Use the context menu in the "Project Explorer" to select we can start the wizard.

 

To do this, we create the class and use the interface IF_RAP_QUERY_PROVIDER, which expects the custom entity.

 

The class now looks like this, but the ABAP Cleaner was also run once here:

CLASS zcl_bs_demo_city_query DEFINITION
  PUBLIC FINAL
  CREATE PUBLIC.

  PUBLIC SECTION.
    INTERFACES if_rap_query_provider.
ENDCLASS.


CLASS zcl_bs_demo_city_query IMPLEMENTATION.
  METHOD if_rap_query_provider~select.
  ENDMETHOD.
ENDCLASS.

 

Core Data Service

In the next step, we create the Core Data Service using the context menu. We use the CDS template "defineCustomEntityWithParameters" as a template:

 

If you chose the wrong template when creating the object, you do not have to delete the object, but can choose a different CDS template. We define two fields, the city we are looking for and a short key that we can also use to search. Since we are using built-in data types, we also set the label and tooltip for the user so that the texts appear in the UI.

@EndUserText.label: 'City Value Help'
@ObjectModel.query.implementedBy: 'ABAP:ZCL_BS_DEMO_CITY_QUERY'
define custom entity ZBS_I_RAPCityVH
{
      @EndUserText.label: 'City'
      @EndUserText.quickInfo: 'Name of the City'
  key City      : abap.char(60);
      @EndUserText.label: 'City (Short)'
      @EndUserText.quickInfo: 'Short name of the City'
      CityShort : abap.char(10);
}

 

Implementation

We have now created the basic elements that we need for the search help. In this section we implement the necessary logic to see data in the UI.

 

Integration

To do this, we bind the search help to the field in the projection view ZBS_C_RAPPartner, using the annotation "Consumption.valueHelpDefinition":

@Consumption.valueHelpDefinition: [{ entity: { name: 'ZBS_I_RAPCityVH', element: 'City' } }]
City,

 

Since value help must also be released externally, you should include the view in your service definition. In the preview it usually works without release, but the lack of access will be noticed after deployment at the latest.

@EndUserText.label: 'Simple Partner Service'
define service ZBS_SIMPLE_PARTNER {
  expose ZBS_C_RAPPartner as Partner;
  expose ZBS_I_RAPCityVH;
}

 

Query class

Let's now extend the query class with the logic we need to be able to use the value help easily. To do this, we need an internal table with the data type of the custom entity. We fill this with the appropriate data.

DATA lt_values TYPE STANDARD TABLE OF ZBS_I_RAPCityVH WITH EMPTY KEY.

lt_values = VALUE #( ( City = 'Walldorf' CityShort = 'DE' )
                     ( City = 'Redmond' CityShort = 'US' )
                     ( City = 'Menlo Park' CityShort = 'US' )
                     ( City = 'Hangzhou' CityShort = 'CN' )
                     ( City = 'Munich' CityShort = 'DE' )
                     ( City = 'Vevey' CityShort = 'CH' )
                     ( City = 'Sankt Petersburg' CityShort = 'RU' )
                     ( City = 'Seattle' CityShort = 'US' )
                     ( City = 'Wolfsburg' CityShort = 'DE' )
                     ( City = 'Cologne' CityShort = 'DE' ) ).

 

To return the data, we still have to call the appropriate REPSONSE methods. Here it is important to only call the methods if the framework requests it, otherwise an error will occur. Therefore, we first ask whether the fields have been requested and then call the method. It is also important that the two methods must always be implemented and should not, for example, be in a TRY/CATCH, where they may not be called if an error occurs.

IF io_request->is_data_requested( ).
  io_response->set_data( lt_values ).
ENDIF.

IF io_request->is_total_numb_of_rec_requested( ).
  io_response->set_total_number_of_records( lines( lt_values ) ).
ENDIF.

 

If we now call up the value help, we unfortunately get no result, the list remains empty.

 

We find the problem in the ABAP Development Tools via the "Feed Reader". Two error messages appear in the Gateway Log.

 

The "Backend Error" is interesting here, as we can find further information about our problem here. We have not called the GET_SORT_ELEMENTS method. However, this is not described in the interface or in the method.

 

In addition to this method, we also have to call the GET_PAGING method, for which we receive a similar error. The call to the methods must be implemented within the method call.

io_request->get_sort_elements( ).
io_request->get_paging( ).

 

If we run the search help again, the data is displayed and we can adopt entries for the filter. This is a very simple search help without much additional information and can be used as a "fixed value help" defined.

 

Extension

The value help works, but no additional functions such as filtering, sorting or paging, which are passed to us from outside. In this section we will also implement these basic functions.

 

Classic ABAP

In classic ABAP there is the helper class /IWBEP/CL_MGW_DATA_UTIL, which has all the methods for filtering data. However, this is not available in ABAP Cloud and in the ABAP Environment.

 

Copy

If you use the class beforehand, you must first convert the RAP objects and structures into the gateway structures. So that we can also work with this function in the cloud, we copy the gateway class and perform a refactoring. Let's look at the ORDERBY method.

DATA: lt_otab  TYPE abap_sortorder_tab,
      ls_oline TYPE abap_sortorder.
DATA: ls_order LIKE LINE OF it_order.

LOOP AT it_order INTO ls_order.
  ls_oline-name = ls_order-property.
  TRANSLATE ls_oline-name TO UPPER CASE. 
  IF ls_order-order = gcs_sorting_order-descending.
    ls_oline-descending = 'X'.
  ENDIF.
  APPEND ls_oline TO lt_otab.
  CLEAR ls_oline.
ENDLOOP.

SORT ct_data BY (lt_otab).

 

After comparing the target structure and using inline declarations, as well as Modern ABAP, the logic is reduced to two lines:

DATA(lt_sort) = CORRESPONDING abap_sortorder_tab( it_sort MAPPING name = element_name ).
SORT ct_data BY (lt_sort).

 

You can find the complete logic of the class in the commit below or directly in the GitHub repository for the latest version.

 

Request

Now we have three methods and a Request object, and we will create a method that takes on the work of carrying out all the necessary steps and calling the methods in the correct order. To do this, we first read all the necessary restrictions from the REQUEST object, such as sorting, pagination and filters.

DATA(lt_sort) = io_request->get_sort_elements( ).
DATA(ld_offset) = io_request->get_paging( )->get_offset( ).
DATA(ld_page_size) = io_request->get_paging( )->get_page_size( ).
TRY.
    DATA(lt_filter) = io_request->get_filter( )->get_as_ranges( ).
  CATCH cx_rap_query_filter_no_range.
    CLEAR lt_filter.
ENDTRY.

 

Then we call the methods in the correct order. Pagination should be done last because we need the correct order and filter before we can generate a snippet of the data.

filter_data( EXPORTING it_filter = lt_filter
             CHANGING  ct_data   = ct_data ).

order_data( EXPORTING it_sort = lt_sort
            CHANGING  ct_data = ct_data ).

page_data( EXPORTING id_offset    = ld_offset
                     id_page_size = ld_page_size
           CHANGING  ct_data      = ct_data ).

 

As a final step, we need to call the logic in our query implementation. To do this, we first note the number of all existing data records before we change the data.

DATA(ld_all_entries) = lines( lt_values ).
NEW zcl_bs_demo_adjust_data( )->adjust_via_request( EXPORTING io_request = io_request
                                                    CHANGING  ct_data    = lt_values ).

 

Result

We have now implemented the basic functions of the search help and can reuse the class. Here is a short demo of the FILTER and SORT functions in the search help.

 

Summary

Here is a short summary of the article and the most important learnings from the implementation.

  • Quick implementation - The implementation of a simple search help without much additional work is carried out with two objects and two adjustments.
  • Service - Inclusion of the entity in the service definition, otherwise the search help cannot be called up later in the test.
  • Hidden mandatory fields - The actual "obligations" when implementing a custom entity query are not quite so transparent. Here you should make sure to call the corresponding methods for request and response.
  • Additional functions - The implementation such as filtering, sorting and paging means a lot of manual effort in development, with Core Data Services everything is already free.

 

Example

You can find all adjustments as Commit in our GitHub repository and you can look at the changes made and new objects in detail there.

 

Conclusion

In this article, you learned how to use the custom entity for your own value helps and what pitfalls you might encounter when implementing it. However, this should not deter you from using the object, as it offers a lot of flexibility.


Included topics:
RAPBTPCustom EntityValue Help
Comments (0)



And further ...

Are you satisfied with the content of the article? We post new content in the ABAP area every Friday and irregularly in all other areas. Take a look at our tools and apps, we provide them free of charge.


RAP - Translation app (example)

Category - ABAP

Let's take a look at a practical example of developing a RAP application in the ABAP environment and how you can create an app with little effort.

08/02/2024

RAP - Deep Action in OData v4

Category - ABAP

In this article we will look at actions with deep structures, how we can create them and pass data to an API endpoint.

05/24/2024

BTP - Connect On-Premise (Consumption Model v2)

Category - ABAP

In this article we want to provide another update on the connection of on-premise systems and how this is done with a communication arrangement.

12/15/2023

RAP - Show app count (Tile)

Category - ABAP

This example is about displaying a counter on the tile of a Fiori Elements application and how such a thing can be implemented.

10/06/2023

RAP - Generator (Fiori)

Category - ABAP

In this article we will look at the more complex RAP generator as a Fiori Elements application and what advantages you have with it.

09/15/2023