Custom Root Entity Use case along with custom messages in RAP

A Custom Entity

A Custom Entity has no real table linked to it. RAP cannot read it automatically. Instead, it creates an empty structure and hands over the control to you. You then write your own ABAP code inside a Query Provider Class (QPC).

Custom Root Entity Example

@EndUserText.label: ‘Custom Root Entity’

@ObjectModel: {
query: {
implementedBy: ‘ABAP:ZCL_SALES_STATUS’
}
}

@UI: {
headerInfo: {
typeName: ‘SalesData’,
typeNamePlural: ‘SalesData’,
title: { value: ‘Salesorder’ },
description: { value: ‘Itemno’ }
}
}

define root custom entity ZCR_CUSTSO_VIEW
{

@UI.lineItem: [{ position: 10 , label: ‘Sales Order’ }]
@Consumption.filter.mandatory: true
@Search.defaultSearchElement: true
@UI.identification:[{ position: 10 , label: ‘Sales Order’}]
key Salesorder : vbeln_va;

@Consumption.filter.mandatory: true
@Search.defaultSearchElement: true
@UI.lineItem: [{ position: 20 , label: ‘Sales Order Item’ }]
@UI.identification: [{ position: 20 , label: ‘Sales Order Item’ }]
key Itemno : posnr_va;

@Consumption.valueHelpDefinition: [{
entity: {
name: ‘ZStatus_VH’, // Your Value Help View
element: ‘Value’ // Source field for Status
},
additionalBinding: [{
localElement: ‘Statusdesc’, // Target field in your app
element: ‘Description’, // Source field from Value Help View
usage: #RESULT // Passes data on selection
}]
}]

@UI.lineItem: [{ position: 30 , label: ‘Sales Order Status’ }]
@UI.identification: [{ position: 30 , label: ‘Sales Order Status’ }]
Status : abap.char( 1 );

@UI.lineItem: [{ position: 40 , label: ‘Time Stamp’ }]
@UI.identification: [{ position: 40 , label: ‘Time Stamp’ }]
Timestamp : timestampl;

@UI.identification: [{ position: 50 , label: ‘Status Description’ }]
@UI.lineItem: [{ position: 50 , label: ‘Status Description’ }]
Statusdesc : abap.char(20);

}

As you have created a Custom Root Entity, you are not forced to fetch data from a database source.

You can validate the input before fetching the data, or you can write your validation logic along with the data retrieval because you are implementing the query yourself.

You can loop over the data, modify it, apply your own business logic, or perform any operation you require before returning the response.

CLASS zcl_sales_status DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .

PUBLIC SECTION.

INTERFACES if_rap_query_provider .

PROTECTED SECTION.
PRIVATE SECTION.

ENDCLASS.

CLASS zcl_sales_status IMPLEMENTATION.

METHOD if_rap_query_provider~select.

DATA(lv_top) = io_request->get_paging( )->get_page_size( ).

IF lv_top < 0.
lv_top = 1.
ENDIF.

DATA(lv_skip) = io_request->get_paging( )->get_offset( ).

DATA(lt_sort) = io_request->get_sort_elements( ).

DATA : lv_orderby TYPE string.

LOOP AT lt_sort INTO DATA(ls_sort).

IF ls_sort-descending = abap_true.
lv_orderby = |'{ lv_orderby } { ls_sort-element_name } DESCENDING |.
ELSE.
lv_orderby = |'{ lv_orderby } { ls_sort-element_name } ASCENDING |.
ENDIF.

ENDLOOP.

IF lv_orderby IS INITIAL.
lv_orderby = ‘Salesorder’.
ENDIF.

DATA(lv_conditions) = io_request->get_filter( )->get_as_sql_string( ).

SELECT FROM zebst_status_log
FIELDS salesorder,
itemno,
status,
statusdesc,
timestamp
WHERE (lv_conditions)
ORDER BY (lv_orderby)
INTO TABLE @DATA(lt_status)
UP TO @lv_top ROWS
OFFSET @lv_skip.

IF lt_status IS INITIAL.

IF lv_conditions IS NOT INITIAL.

RAISE EXCEPTION TYPE zcx_rap_exception_provider
EXPORTING
textid = VALUE scx_t100key(

* HOW TO ADD CUSTOM MESSAGE CREATED IN SE91 (ZMSG_STATUS)

msgid = ‘ZMSG_STATUS’
msgno = ‘000’
)
previous = NEW cx_sadl_contract_violation( ).

ELSEIF lv_conditions IS INITIAL.

RAISE EXCEPTION TYPE zcx_rap_exception_provider
EXPORTING
textid = VALUE scx_t100key(

* HOW TO ADD CUSTOM MESSAGE CREATED IN SE91 (ZMSG_STATUS)

msgid = ‘ZMSG_STATUS’
msgno = ‘001’
)
previous = NEW cx_sadl_contract_violation( ).

ENDIF.

ELSE.

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

ENDIF.

ENDMETHOD.

ENDCLASS.

Using this approach, you can display a custom message when the user clicks the Go button.

In Managed and Unmanaged RAP scenarios, it is not straightforward to display this type of validation message during the read operation because the framework handles the data retrieval automatically. However, with a Custom Root Entity and Query Provider Class, you have complete control over the query execution and can perform validations before returning the data.

Custom Exception Class

To display custom messages, you need to create a custom exception class by inheriting from the standard RAP Query Provider exception class.

CLASS zcx_rap_exception_provider DEFINITION
PUBLIC
INHERITING FROM cx_rap_query_provider
FINAL
CREATE PUBLIC .

PUBLIC SECTION.

METHODS constructor
IMPORTING
!textid LIKE if_t100_message=>t100key OPTIONAL
!previous LIKE previous OPTIONAL.

PROTECTED SECTION.
PRIVATE SECTION.

ENDCLASS.

CLASS zcx_rap_exception_provider IMPLEMENTATION.

METHOD constructor ##ADT_SUPPRESS_GENERATION.

CALL METHOD super->constructor
EXPORTING
previous = previous.

CLEAR me->textid.

IF textid IS INITIAL.
if_t100_message~t100key = if_t100_message=>default_textid.
ELSE.
if_t100_message~t100key = textid.
ENDIF.

ENDMETHOD.

ENDCLASS.

After creating this custom exception class, you can use your custom SE91 message class (for example, ZMSG_STATUS) to display meaningful validation messages directly in the Fiori application when the user clicks the Go button.

This approach gives you complete control over the read operation. You can validate user input, fetch data from any source, modify the retrieved data, implement custom business logic, and raise custom exceptions whenever required.

 

​ A Custom EntityA Custom Entity has no real table linked to it. RAP cannot read it automatically. Instead, it creates an empty structure and hands over the control to you. You then write your own ABAP code inside a Query Provider Class (QPC).Custom Root Entity Example@EndUserText.label: ‘Custom Root Entity’

@ObjectModel: {
query: {
implementedBy: ‘ABAP:ZCL_SALES_STATUS’
}
}

@UI: {
headerInfo: {
typeName: ‘SalesData’,
typeNamePlural: ‘SalesData’,
title: { value: ‘Salesorder’ },
description: { value: ‘Itemno’ }
}
}

define root custom entity ZCR_CUSTSO_VIEW
{

@UI.lineItem: [{ position: 10 , label: ‘Sales Order’ }]
@Consumption.filter.mandatory: true
@Search.defaultSearchElement: true
@UI.identification:[{ position: 10 , label: ‘Sales Order’}]
key Salesorder : vbeln_va;

@Consumption.filter.mandatory: true
@Search.defaultSearchElement: true
@UI.lineItem: [{ position: 20 , label: ‘Sales Order Item’ }]
@UI.identification: [{ position: 20 , label: ‘Sales Order Item’ }]
key Itemno : posnr_va;

@Consumption.valueHelpDefinition: [{
entity: {
name: ‘ZStatus_VH’, // Your Value Help View
element: ‘Value’ // Source field for Status
},
additionalBinding: [{
localElement: ‘Statusdesc’, // Target field in your app
element: ‘Description’, // Source field from Value Help View
usage: #RESULT // Passes data on selection
}]
}]

@UI.lineItem: [{ position: 30 , label: ‘Sales Order Status’ }]
@UI.identification: [{ position: 30 , label: ‘Sales Order Status’ }]
Status : abap.char( 1 );

@UI.lineItem: [{ position: 40 , label: ‘Time Stamp’ }]
@UI.identification: [{ position: 40 , label: ‘Time Stamp’ }]
Timestamp : timestampl;

@UI.identification: [{ position: 50 , label: ‘Status Description’ }]
@UI.lineItem: [{ position: 50 , label: ‘Status Description’ }]
Statusdesc : abap.char(20);

}As you have created a Custom Root Entity, you are not forced to fetch data from a database source.You can validate the input before fetching the data, or you can write your validation logic along with the data retrieval because you are implementing the query yourself.You can loop over the data, modify it, apply your own business logic, or perform any operation you require before returning the response.CLASS zcl_sales_status DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .

PUBLIC SECTION.

INTERFACES if_rap_query_provider .

PROTECTED SECTION.
PRIVATE SECTION.

ENDCLASS.

CLASS zcl_sales_status IMPLEMENTATION.

METHOD if_rap_query_provider~select.

DATA(lv_top) = io_request->get_paging( )->get_page_size( ).

IF lv_top < 0.
lv_top = 1.
ENDIF.

DATA(lv_skip) = io_request->get_paging( )->get_offset( ).

DATA(lt_sort) = io_request->get_sort_elements( ).

DATA : lv_orderby TYPE string.

LOOP AT lt_sort INTO DATA(ls_sort).

IF ls_sort-descending = abap_true.
lv_orderby = |'{ lv_orderby } { ls_sort-element_name } DESCENDING |.
ELSE.
lv_orderby = |'{ lv_orderby } { ls_sort-element_name } ASCENDING |.
ENDIF.

ENDLOOP.

IF lv_orderby IS INITIAL.
lv_orderby = ‘Salesorder’.
ENDIF.

DATA(lv_conditions) = io_request->get_filter( )->get_as_sql_string( ).

SELECT FROM zebst_status_log
FIELDS salesorder,
itemno,
status,
statusdesc,
timestamp
WHERE (lv_conditions)
ORDER BY (lv_orderby)
INTO TABLE @DATA(lt_status)
UP TO @lv_top ROWS
OFFSET @lv_skip.

IF lt_status IS INITIAL.

IF lv_conditions IS NOT INITIAL.

RAISE EXCEPTION TYPE zcx_rap_exception_provider
EXPORTING
textid = VALUE scx_t100key(

* HOW TO ADD CUSTOM MESSAGE CREATED IN SE91 (ZMSG_STATUS)

msgid = ‘ZMSG_STATUS’
msgno = ‘000’
)
previous = NEW cx_sadl_contract_violation( ).

ELSEIF lv_conditions IS INITIAL.

RAISE EXCEPTION TYPE zcx_rap_exception_provider
EXPORTING
textid = VALUE scx_t100key(

* HOW TO ADD CUSTOM MESSAGE CREATED IN SE91 (ZMSG_STATUS)

msgid = ‘ZMSG_STATUS’
msgno = ‘001’
)
previous = NEW cx_sadl_contract_violation( ).

ENDIF.

ELSE.

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

ENDIF.

ENDMETHOD.

ENDCLASS.Using this approach, you can display a custom message when the user clicks the Go button.In Managed and Unmanaged RAP scenarios, it is not straightforward to display this type of validation message during the read operation because the framework handles the data retrieval automatically. However, with a Custom Root Entity and Query Provider Class, you have complete control over the query execution and can perform validations before returning the data.Custom Exception ClassTo display custom messages, you need to create a custom exception class by inheriting from the standard RAP Query Provider exception class.CLASS zcx_rap_exception_provider DEFINITION
PUBLIC
INHERITING FROM cx_rap_query_provider
FINAL
CREATE PUBLIC .

PUBLIC SECTION.

METHODS constructor
IMPORTING
!textid LIKE if_t100_message=>t100key OPTIONAL
!previous LIKE previous OPTIONAL.

PROTECTED SECTION.
PRIVATE SECTION.

ENDCLASS.

CLASS zcx_rap_exception_provider IMPLEMENTATION.

METHOD constructor ##ADT_SUPPRESS_GENERATION.

CALL METHOD super->constructor
EXPORTING
previous = previous.

CLEAR me->textid.

IF textid IS INITIAL.
if_t100_message~t100key = if_t100_message=>default_textid.
ELSE.
if_t100_message~t100key = textid.
ENDIF.

ENDMETHOD.

ENDCLASS.After creating this custom exception class, you can use your custom SE91 message class (for example, ZMSG_STATUS) to display meaningful validation messages directly in the Fiori application when the user clicks the Go button.This approach gives you complete control over the read operation. You can validate user input, fetch data from any source, modify the retrieved data, implement custom business logic, and raise custom exceptions whenever required.   Read More Technology Blog Posts by SAP articles 

#SAP

#SAPTechnologyblog

You May Also Like

More From Author