In modern SAP application development using the ABAP RESTful Application Programming Model, developers often encounter scenarios where data must be retrieved from multiple sources instead of a single database table.
For such cases, Custom Entities provide a flexible solution. They allow developers to implement custom query logic using ABAP classes while still leveraging RAP features such as associations, navigation, and UI annotations.
In this blog, we will implement a Travel–Booking scenario using Custom Entities where data is fetched dynamically through a query implementation class.
First, create a class that implements the RAP interface:
INTERFACE if_rap_query_providerThis interface allows developers to implement custom query logic.
CLASS zcl_custom_entitys DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
" Interface used for implementing query logic for Custom Entities
INTERFACES if_rap_query_provider.
ENDCLASS.
CLASS zcl_custom_entitys IMPLEMENTATION.
METHOD if_rap_query_provider~select.
" Variables used for paging, entity identification and filtering
DATA: lv_top TYPE i,
lv_offset TYPE i,
lv_entity TYPE string,
lv_conditions TYPE string,
lv_total TYPE int8.
" Read paging parameters from OData request
lv_top = io_request->get_paging( )->get_page_size( ).
lv_offset = io_request->get_paging( )->get_offset( ).
" Identify which custom entity is being queried
lv_entity = io_request->get_entity_id( ).
" Ensure page size is valid
IF lv_top < 0.
lv_top = 1.
ENDIF.
" Retrieve filter conditions from request
lv_conditions = io_request->get_filter( )->get_as_sql_string( ).
" Handle Travel Custom Entity request
IF lv_entity = 'ZI_TRAVEL_CUSTOMENTITY'.
" Fetch data from travel table with paging and filter conditions
SELECT travel_id,
agency_id,
customer_id,
begin_date,
end_date,
booking_fee,
total_price,
currency_code,
description,
CASE
WHEN overall_status = 'O' THEN 'Open'
WHEN overall_status = 'A' THEN 'Accepted'
WHEN overall_status = 'X' THEN 'Cancel'
END AS overall_status
FROM /dmo/travel_m
WHERE (lv_conditions)
ORDER BY travel_id, agency_id
INTO TABLE (lt_travel)
OFFSET _offset
UP TO _top ROWS.
" Calculate number of records returned
lv_total = lines( lt_travel ).
" Send response back to RAP framework
io_response->set_data( lt_travel ).
io_response->set_total_number_of_records( lv_total ).
ENDIF.
ENDMETHOD.
ENDCLASS.This class dynamically fetches data using paging parameters such as $top and $skip.
Next, define the root custom entity in CDS.
@EndUserText.label: 'Travel Custom Entity'
@ObjectModel: {
query.implementedBy: 'ABAP:ZCL_CUSTOM_ENTITYS'
}
@Metadata.allowExtensions: true
define root custom entity Zi_travel_customentity
{
key Travel_id : /dmo/travel_id;
Agency_id : /dmo/agency_id;
Customer_id : /dmo/customer_id;
Begin_date : /dmo/begin_date;
End_date : /dmo/end_date;
@Semantics.amount.currencyCode: 'currency_code'
booking_fee : /dmo/booking_fee;
@Semantics.amount.currencyCode: 'currency_code'
Total_price : /dmo/total_price;
currency_code : /dmo/currency_code;
description : /dmo/description;
overall_status : abap.char(10);
_Booking : composition [1..*] of ZI_BOOKING_CUSTOMENTITY;
}Now create the booking entity and associate it with Travel.
@EndUserText.label: 'Booking Entity'
@ObjectModel : {
query.implementedBy: 'ABAP:ZCL_CUSTOM_ENTITYS'
}
@Metadata.allowExtensions: true
define custom entity ZI_BOOKING_CUSTOMENTITY
{
key travel_id : /dmo/travel_id;
key booking_id : /dmo/booking_id;
booking_date : /dmo/booking_date;
customer_id : /dmo/customer_id;
carrier_id : /dmo/carrier_id;
connection_id: /dmo/connection_id;
flight_date : /dmo/flight_date;
@Semantics.amount.currencyCode: 'currency_code'
flight_price : /dmo/flight_price;
currency_code : /dmo/currency_code;
booking_status: /dmo/booking_status;
_Travel : association to parent Zi_travel_customentity
on $projection.travel_id = _Travel.Travel_id;
}Metadata extensions are used to define how the fields appear in SAP Fiori applications.
Example:
.selectionField: [{ position: 10 }]
@UI.lineItem: [{ position: 10 }]
@UI.identification: [{ position: 10 }]
Travel_id;Expose the root entity using a service definition.
define service ZUI_TRAVEL_SERVICE {
expose Zi_travel_customentity;
}Create a Service Binding for the service definition and activate it to expose the service as an OData service.
Preview the Application
Using Custom Entities in unmanaged RAP provides several benefits:
• Fetch data from multiple data sources
• Implement custom query logic using ABAP
• Enable associations and navigation
• Support Fiori UI annotations
• Integrate easily with OData services
Conclusion
Custom Entities are a powerful feature in the ABAP RESTful Application Programming Model that allow developers to implement flexible data retrieval scenarios.
By combining CDS definitions, query implementation classes, and metadata extensions, developers can build scalable services capable of fetching data from multiple sources while still benefiting from RAP architecture.
This approach is particularly useful in scenarios where data cannot be represented by a single CDS view or database table.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
| User | Count |
|---|---|
| 16 | |
| 7 | |
| 6 | |
| 6 | |
| 4 | |
| 4 | |
| 3 | |
| 3 | |
| 2 | |
| 2 |