Implement a CDS Custom Entity and Query Implementation Class
- How to implement a query manually for your CDS custom entity
- How to display the data retrieved in a Fiori Elements preview
Prerequisites
- IMPORTANT: This tutorial cannot be completed on a trial account
- IMPORTANT: This tutorial is part 4 of a mission. You must complete the other 3 parts first; otherwise, you may experience errors or unexpected behavior. The link to the mission is available at the top right of the screen, immediately above the list of steps.
This tutorial is based on:
- Using a CDS Custom Entity for Data Modeling.
- Implementing the Query for Service Consumption
- Implementing Data and Count Retrieval
Therefore, this tutorial will only cover in detail those aspects that are different. In this case, you are not including both remote and local data, you are only retrieving local data. Therefore, you do not need to include the local calculated fields, DiscountPct
and DiscountAbs
.
More Information
- Step 1
First, you create the class that implements the data retrieval logic.
-
In ADT, open your package
Z_A4C_TO_A4C_XX2
and choose New > Class. -
Enter a name and description:
ZCL_TRAVELS_XXX
- Get travel data from A4C System
-
Accept the default transport request, then choose Finish.
-
- Step 2
The signature of the method
IF_RAP_QUERY_PROVIDER~SELECT
contains the import parameterio_request
. This parameter represents the OData query options that are delegated from the UI and used as input for the SELECT method.Whenever the OData client requests data, the query implementation class must return the data that matches the request, or throw an exception if the request cannot be fulfilled.
-
Implement the interface by adding this statement to the public section:
INTERFACES if_rap_query_provider.
-
Choose Quick Fix (
Ctrl+1
), then choose Add implementation for SELECT…. -
Save and activate ( Ctrl+S, Ctrl+F3 ) your class.
Later, you will implement the SELECT method of the interface.
-
- Step 3
-
Open your CDS custom entity
ZCE_TRAVEL_DATA_XXX
, created in Create a Service Consumption Model. -
Add the following annotation to the view (immediately after the ‘@EndUserText.label’ annotation), pointing to the class you have just created - NOTE: Use upper case!
CDSCopy
@ObjectModel.query.implementedBy: 'ABAP:ZCL_TRAVELS_XXX'
-
- Step 4
Copy the following code into your query implementation class,
ZCL_TRAVELS_XXX
. Ignore the warnings.ABAPCopyCLASS zcl_travels_xxx DEFINITION PUBLIC FINAL CREATE PUBLIC . PUBLIC SECTION. INTERFACES if_rap_query_provider. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS zcl_travels_xxx IMPLEMENTATION. METHOD if_rap_query_provider~select. """Instantiate Client Proxy DATA(lo_client_proxy) = zcl_proxy_travels_xxx=>get_client_proxy( ). TRY. """Instantiate Client Proxy """Create Read Request DATA(lo_read_request) = lo_client_proxy->create_resource_for_entity_set( 'TRAVEL' )->create_request_for_read( ). """Request Inline Count IF io_request->is_total_numb_of_rec_requested( ). io_response->set_total_number_of_records( lo_response->get_count( ) ). ENDIF. """Implement Paging DATA(ls_paging) = io_request->get_paging( ). IF ls_paging->get_offset( ) >= 0. lo_read_request->set_skip( ls_paging->get_offset( ) ). ENDIF. IF ls_paging->get_page_size( ) <> if_rap_query_paging=>page_size_unlimited. lo_read_request->set_top( ls_paging->get_page_size( ) ). """Execute the Request DATA(lo_response) = lo_read_request->execute( ). ENDIF. CATCH /iwbep/cx_gateway INTO DATA(lx_gateway). RAISE EXCEPTION TYPE ZCX_TRAVELS_CONS_XXX EXPORTING textid = ZCX_TRAVELS_CONS_XXX=>query_fail previous = lx_gateway. ENDTRY. ENDMETHOD. ENDCLASS.
- Step 5
-
Add the variables you need using the
DATA
statement.-
lt_travel
= internal table of the generated abstract entity,ZTRAVEL
orZTRAVEL+10-digit-GUID
, created in tutorial Create a Service Consumption Model. The data from the remote service will be written into that table. -
lt_travel_ce
= internal table of the custom entity,zce_travels_xxx
, created in step 3 above. This table is used to fill the output parameter of the select method.
ABAPCopy
"""Define variables IF io_request->is_data_requested( ). DATA: "abstract entity; receives data from remote service lt_travel TYPE STANDARD TABLE OF ZTRAVEL, "custom entity; fills output parameter of SELECT lt_travel_ce TYPE STANDARD TABLE OF zce_travel_data_pmd. ENDIF. -
-
Get the data from the response object of your remote service, and write it to
lt_travel
.ABAPCopy"""Get data lo_response->get_business_data( IMPORTING et_business_data = lt_travel ).
-
If
lt_travel
returns entries, provide a mapping for those elements in the custom entity that are not identical with the names of the abstract entity elements - in this case, Description.ABAPCopy"""Check if lt_travel returns entries; map elements IF lt_travel IS NOT INITIAL. lt_travel_ce = CORRESPONDING #( lt_travel MAPPING description = memo calculatedetag = lastchangedat ). ENDIF.
-
Set return data.
ABAPCopy"""Set return data io_response->set_data( lt_travel_ce ). ENDIF.
-
Save and activate (
Ctrl+S, Ctrl+F3
) the class.
-
- Step 6ABAPCopy
CLASS zcl_travels_xxx DEFINITION PUBLIC FINAL CREATE PUBLIC . PUBLIC SECTION. INTERFACES if_rap_query_provider. PROTECTED SECTION. PRIVATE SECTION. ENDCLASS. CLASS zcl_travels_xxx IMPLEMENTATION. METHOD if_rap_query_provider~select. """Instantiate Client Proxy DATA(lo_client_proxy) = zcl_proxy_travels_xxx=>get_client_proxy( ). TRY. """ Instantiate Client Proxy """ Create Read Request DATA(lo_read_request) = lo_client_proxy->create_resource_for_entity_set( 'TRAVEL' )->create_request_for_read( ). """ Request Inline Count IF io_request->is_total_numb_of_rec_requested( ). io_response->set_total_number_of_records( lo_response->get_count( ) ). ENDIF. """ Implement Paging DATA(ls_paging) = io_request->get_paging( ). IF ls_paging->get_offset( ) >= 0. lo_read_request->set_skip( ls_paging->get_offset( ) ). ENDIF. IF ls_paging->get_page_size( ) <> if_rap_query_paging=>page_size_unlimited. lo_read_request->set_top( ls_paging->get_page_size( ) ). """ Execute the Request DATA(lo_response) = lo_read_request->execute( ). ENDIF. """ Define variables IF io_request->is_data_requested( ). DATA: "abstract entity; receives data from remote service lt_travel TYPE STANDARD TABLE OF ztravelf7fb77ae54, "custom entity; fills output param of SELECT lt_travel_ce TYPE STANDARD TABLE OF zce_travel_data_pmd, "local db table lt_traveladd TYPE STANDARD TABLE OF zttravels_pmd. """ Get data from response object lo_response->get_business_data( IMPORTING et_business_data = lt_travel ). """ Check if lt_travel returns entries, then pass data to internal table for custom entity IF lt_travel IS NOT INITIAL. lt_travel_ce = CORRESPONDING #( lt_travel MAPPING description = memo calculatedetag = lastchangedat ). ENDIF. """ Set return data io_response->set_data( lt_travel_ce ). ENDIF. CATCH /iwbep/cx_gateway INTO DATA(lx_gateway). RAISE EXCEPTION TYPE ZCX_TRAVELS_CONS_XXX EXPORTING textid = ZCX_TRAVELS_CONS_XXX=>query_fail previous = lx_gateway. ENDTRY. ENDMETHOD. ENDCLASS.
- Step 7
-
Select your service definition,
ZCE_TRAVEL_DATA_XXX
, created in the tutorial Create a Service Consumption Model and choose New > Create Service Binding from the context menu. -
In the wizard:
- Enter a name:
Z_BIND_TRAVELS_XXX
and description Bind Travels Service - Enter the binding type:
ODATA V2 - Web API
- Choose Next
- Enter a name:
-
Accept the transport request and choose Finish.
The service binding opens in a new editor.
-
Choose Activate.
On the left is the Service Definition,
ZCE_TRAVEL_DATA_XXX
.
On the right, is the active service, including the Entity Set and the Service URL. -
Select the entity Set Travel and choose Preview.
The Fiori Elements preview for your remote OData service appears in the browser, but without any data.
-
Choose Settings > Select All > OK, then choose Go.
Your Fiori Elements preview should look roughly like this:
-
- Step 8
If the data appears, you can now improve the look and feel of your preview.
-
Make the first five column headers appear automatically when the app appears (without your having to select them in settings), by adding the following annotations:
CDSCopy@UI.lineItem: [ { position: 10 } ] key TravelID : abap.numc( 8 ); @UI.lineItem: [ { position: 20 } ] AgencyID : abap.numc( 6 ); @UI.lineItem: [ { position: 30 } ] CustomerID : abap.numc( 6 ); @UI.lineItem: [ { position: 40, label: 'Start Date'} ] BeginDate : rap_cp_odata_v2_edm_datetime; @UI.lineItem: [ { position: 50, label: 'End Date'} ] EndDate : rap_cp_odata_v2_edm_datetime;
-
The two headings
RESTful
ABAP Programming: Data Type… are ugly. Change them to Begin Date and End Date by adding labels, as follows:CDSCopy@UI.lineItem: [ { position: 40, label: 'Start Date'} ] BeginDate : rap_cp_odata_v2_edm_datetime; @UI.lineItem: [ { position: 50, label: 'End Date'} ] EndDate : rap_cp_odata_v2_edm_datetime;
-
- Step 9
Your code should now look like this.
ABAPCopy@EndUserText.label: 'Travel data custom entity in PMD' @ObjectModel.query.implementedBy: 'ABAP:ZCL_TRAVELS_PMD' define custom entity ZCE_TRAVEL_DATA_PMD { @UI.lineItem: [ { position: 10 } ] key TravelID : abap.numc( 8 ); @UI.lineItem: [ { position: 20 } ] AgencyID : abap.numc( 6 ); @UI.lineItem: [ { position: 30 } ] CustomerID : abap.numc( 6 ); @UI.lineItem: [ { position: 40, label: 'Start Date'} ] BeginDate : rap_cp_odata_v2_edm_datetime; @UI.lineItem: [ { position: 50, label: 'End Date'} ] EndDate : rap_cp_odata_v2_edm_datetime; @Semantics.amount.currencyCode: 'CurrencyCode' BookingFee : abap.dec( 17, 3 ); @Semantics.amount.currencyCode: 'CurrencyCode' TotalPrice : abap.dec( 17, 3 ); @Semantics.currencyCode: true CurrencyCode : abap.cuky( 5 ); Description : abap.char( 1024 ); //renamed element Status : abap.char( 1 ); LastChangedAt : tzntstmpl; CalculatedEtag : abap.string( 0 ); }
The SAP Fiori elements preview should now open looking like this.
- Step 10
Which of the following is the correct syntax to create a read request for the entity set PRODUCT ?
- Step 11
You can test your message class, for example by commenting out the value
i_service_instance_name
in the classzcl_proxy_travels_xx2
and changing it to a non-existent value.When you run the application, by choosing Go in the Fiori Elements preview, then you should get an error message like this:
- Step 12
If you are having problems, you can trace the flow of your application in ABAP Debugger.
-
For example, set a breakpoint at this statement:
lt_travel_ce = CORRESPONDING #( lt_travel MAPPING description = memo calculatedetag = lastchangedat ).
-
You can then see whether the two internal tables have been filled.
-
- Create class implementing data retrieval logic
- Add INTERFACES statement
- Specify class in your custom entity
- Copy code
- Implement SELECT method in query implementation class
- Check the code for your query implementation class
- Create service binding
- Refine UI
- Check the code for your custom entity
- Test yourself
- Test message class (optional)
- Debugging