This post explores how virtual elements can be defined in a CDS View Entity.
What are Virtual elements?
Virtual elements are columns that are not stored in the source database table but are calculated at runtime. Virtual elements represent transient fields in business applications. They are defined at the level of CDS consumption views as additional elements within the SELECT
list using specific @DataModel
annotations.
Defining Virtual Elements in CDS Views
Virtual Elements are defined using annotations including below. The virtual element logic is implemented in the class specified.
@ObjectModel.virtualElement
@ObjectModel.virtualElementCalculatedBy: 'ABAP:className'
Steps
- Create a CDS View
- Create a class to implement the virtual element calculation logic
- Test the Virtual Elements
Create a CDS View
Choose New > Data Definition.
Provide Name and Description and click Next. Choose TR, then choose the template for Define View
and click Finish.
Complete the code.

@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Virtual Elements in CDS'
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.usageType:{
serviceQuality: #X,
sizeCategory: #S,
dataClass: #MIXED
}
define root view entity ZJP_Virtual_element
as select from sflight
{
key carrid as Carrid,
key connid as Connid,
key fldate as Fldate,
@Semantics.amount.currencyCode: 'Currency'
price as Price,
currency as Currency,
planetype as Planetype,
seatsmax as Seatsmax,
seatsocc as Seatsocc,
@Semantics.amount.currencyCode: 'Currency'
paymentsum as Paymentsum,
seatsmax_b as SeatsmaxB,
seatsocc_b as SeatsoccB,
seatsmax_f as SeatsmaxF,
seatsocc_f as SeatsoccF,
@ObjectModel.virtualElementCalculatedBy: 'ABAP:ZCL_VIRTUAL_ELEMENT_CALC'
@EndUserText.label: 'Available Seats'
@ObjectModel.virtualElement: true
cast( 0 as abap.int4 ) as SeatsAvailable,
@ObjectModel.virtualElementCalculatedBy: 'ABAP:ZCL_VIRTUAL_ELEMENT_CALC'
@EndUserText.label: 'Week Day'
@ObjectModel.virtualElement: true
cast( '' as abap.char(9) ) as dayOfTheFlight
}
Create Implementation Class
Create the class and add an interface if_sadl_exit_calc_element_read
. Methods calculate
and get_calculation_info
from the interface needs to be implemented.


CLASS zcl_virtual_element_calc DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_sadl_exit_calc_element_read.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS ZCL_VIRTUAL_ELEMENT_CALC IMPLEMENTATION.
METHOD if_sadl_exit_calc_element_read~calculate.
CHECK NOT it_original_data IS INITIAL.
DATA : lt_calculated_data TYPE STANDARD TABLE OF ZJP_Virtual_element WITH DEFAULT KEY.
MOVE-CORRESPONDING it_original_data TO lt_calculated_data.
LOOP AT lt_calculated_data ASSIGNING FIELD-SYMBOL(<flight>).
<flight>-SeatsAvailable = <flight>-Seatsmax - <flight>-Seatsocc.
<flight>-dayOfTheFlight = cl_reca_date=>get_weekday( <flight>-Fldate ).
ENDLOOP.
MOVE-CORRESPONDING lt_calculated_data TO ct_calculated_data.
ENDMETHOD.
METHOD if_sadl_exit_calc_element_read~get_calculation_info.
et_requested_orig_elements = VALUE #( BASE et_requested_orig_elements
( CONV #( 'SEATSOCC' ) )
( CONV #( 'SEATSMAX' ) )
( CONV #( 'FLDATE' ) )
).
ENDMETHOD.
ENDCLASS.
Test the Virtual Elements
If you just execute the CDS view the virtual elements are not calculated. If the CDS view is used in the ABAP query, the experience is the same.

To see the virtual elements results, we need to expose the CDS to OData. This can be done in 2 ways.
Test using OData.Publish
1. Add annotation – @OData.publish: true
Add the annotation and activate the CDS view.

A service is generated automatically. The warning icon shows additional information that the service is not yet registered.

2. Register the service
Register the service using transaction /n/iwfnd/maint_service


3. Test using gateway client using transaction – /IWFND/GW_CLIENT
HTTP Method - GET
Request URI - /sap/opu/odata/sap/ZJP_VIRTUAL_ELEMENT_CDS/ZJP_Virtual_element

Testing using RAP
1. Create a projection view

@AccessControl.authorizationCheck: #NOT_REQUIRED
@Metadata.allowExtensions: true
@EndUserText.label: 'Projection Entity for Carrier'
@ObjectModel.semanticKey: [ 'Connid' ]
define root view entity ZJP_C_Virtual_element
as select from ZJP_Virtual_element
{
@UI.lineItem: [{ position: 10 }]
key Carrid,
@UI.lineItem: [{ position: 20 }]
key Connid,
@UI.lineItem: [{ position: 30 }]
key Fldate,
@UI.lineItem: [{ position: 40 }]
Seatsmax,
@UI.lineItem: [{ position: 50 }]
Seatsocc,
SeatsmaxB,
SeatsoccB,
SeatsmaxF,
SeatsoccF,
@UI.lineItem: [{ position: 60 }]
SeatsAvailable,
@UI.lineItem: [{ position: 70 }]
dayOfTheFlight
}
2. Create Service Definition
Behavior definition is not needed as we only need to test the display.

@EndUserText.label: 'test'
define service ZJP_SD_VE {
expose ZJP_C_Virtual_element;
}
3. Create and publish service binding


Visit ABAP on HANA series for Tutorials on CDS, AMDP, Eclipse, and ALV IDA.
If you like the content, please subscribe…