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

  1. Create a CDS View
  2. Create a class to implement the virtual element calculation logic
  3. 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.

  1. Create a service using OData.Publish annotation
  2. Create a RAP Service

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…

Join 4,016 other subscribers

Discovering ABAP YouTube Channel