Advertising:

Virtual fields in CDS Views: Difference between revisions

From SAP Knowledge Base
(Created page with "It is often necessary to supply data in a CDS view, as simple connections/relationships through CDS views are not possible and more complex coding is required. The calculation logic, in particular, is used to fill a field with a specific value. For performance reasons, you should use it as sparingly as possible. In my case, I developed an app with RAP and was able to map it completely using CDS views except for a few columns. == Introduction == Virtual fields are imp...")
 
No edit summary
Line 1: Line 1:
[[category: Core_data_services]]
It is often necessary to supply data in a CDS view, as simple connections/relationships through CDS views are not possible and more complex coding is required. The calculation logic, in particular, is used to fill a field with a specific value. For performance reasons, you should use it as sparingly as possible.
It is often necessary to supply data in a CDS view, as simple connections/relationships through CDS views are not possible and more complex coding is required. The calculation logic, in particular, is used to fill a field with a specific value. For performance reasons, you should use it as sparingly as possible.



Revision as of 14:02, 5 January 2025

It is often necessary to supply data in a CDS view, as simple connections/relationships through CDS views are not possible and more complex coding is required. The calculation logic, in particular, is used to fill a field with a specific value. For performance reasons, you should use it as sparingly as possible.

In my case, I developed an app with RAP and was able to map it completely using CDS views except for a few columns.

Introduction

Virtual fields are implemented with ABAP classes and have been available since SAP NetWeaver Release 7.51.

A distinction is made between three categories:

  • virtual fields with their own calculation logic
  • virtual fields with their own sort logic
  • virtual fields with their own filter logic

A few facts:

  • Virtual fields are only addressed within the OData framework. Queries of the CDS view via Open SQL Selects return no results, i.e. the underlying class is not run through
  • Virtual fields do not know each other
  • Filter logic cannot be applied to virtual fields and is explicitly intercepted in the further SADL code
  • Key fields cannot be defined as virtual elements

Declaration in CDS view using the example of calculation logic

Virtual fields can be used where they are supported, e.g. in EXTEND VIEW ENTITY:

define view <CdsConsumptionView>
		as select from <data_source>
{
		...
		@ObjectModel.readOnly: true
		@ObjectModel.virtualElement
		@ObjectModel.virtualElementCalculatedBy: 'ABAP:<code_exit_class>'
		cast( '' as <dtype> preserving type) as <view.element>
		...
}

The notation is slightly different in projection views:

define root view entity <CdsProjectionView>
  provider contract transactional_query
  as projection on <data_source>
{
       ...
       @ObjectModel. virtualElementCalculatedBy: 'ABAP:<code_exit_class>'
       virtual <view.element> : abap.<type>
       ...
}

Similarly for filtering and sorting, see useful pages.

Exit classes

For the three possible cases of virtual elements, a class must be created that is marked with a marker, i.e. INTERFACE, so that the method header is used as specified in the INTERFACE. How the method body is programmed can be seen as follows for all logics.

Calculation logic

For a bonus and analysis app, it was necessary to calculate the current turnover. This could not simply be determined using CDS views and had to be calculated.

I got into the habit of designating the exit class as a suffix with _CALC.

CDS-View
		...
		@ObjectModel. virtualElementCalculatedBy: 'ABAP:YCL_CCM_AMOUNT_CALC'
		virtual amount              : abap.dec( 13,2 ), //abap.dec( 15,2 ), //wcb_scale
		...
CLASS ycl_ccm_amount_calc DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.
    INTERFACES if_sadl_exit_calc_element_read.
  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.

CLASS ycl_ccm_amount_calc IMPLEMENTATION.

  METHOD if_sadl_exit_calc_element_read~calculate.

    DATA orig_data TYPE STANDARD TABLE OF <cds_view_with_exit_class>.
    FIELD-SYMBOLS <orig_data> TYPE <cds_view_with_exit_class>.

    MOVE-CORRESPONDING it_original_data TO orig_data.

    LOOP AT orig_data ASSIGNING <orig_data>.

      try.
       <orig_data>-amount = <method_of_a_class>
     catch cx_root into DATA(cx).
       <orig_data>-amount = 0.
      endtry.

    ENDLOOP.
    MOVE-CORRESPONDING orig_data TO ct_calculated_data.

  ENDMETHOD.

It is possible to use the get_calculation_info method to add only the required elements or to check whether the correct CDS view triggers this class.

 METHOD if_sadl_exit_calc_element_read~get_calculation_info.

  IF iv_entity <> '<your_cds_view'.
   RAISE EXCEPTION TYPE ...
  ENDIF.
 
  IF line_exists( it_requested_calc_elements[table_line = 'XYZ' ] ) .
   INSERT: conv sadl_entity_element( 'field' ) INTO TABLE et_requested_orig_elements.
  ENDIF.

 ENDMETHOD.

Sort logic

CLASS <classname> DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .
 
  PUBLIC SECTION.
    INTERFACES if_sadl_exit_sort_transform.
 
  PROTECTED SECTION.
 
  PRIVATE SECTION.
 
ENDCLASS.

CLASS <classname> IMPLEMENTATION.
 
  METHOD if_sadl_exit_sort_transform~map_element.
 
    IF iv_entity <> '<cds_view_name>'.
      RAISE EXCEPTION TYPE ...
    ENDIF.
 
    IF iv_element = 'AMOUNT'.
      et_sort_elements = VALUE #(
        ( name = 'AMOUNT' ) ( name = 'CONDITIONCONTRACT' )
      ).
    ENDIF.
 
  ENDMETHOD.
 
ENDCLASS.

Filter logic

CLASS <classname> DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .
 
  PUBLIC SECTION.
    INTERFACES if_sadl_exit_filter_transform.
 
  PROTECTED SECTION.
 
  PRIVATE SECTION.
 
ENDCLASS.

CLASS <classname> IMPLEMENTATION.
 METHOD if_sadl_exit_filter_transform~map_atom.
  DATA: condition_manager TYPE REF TO if_sadl_simple_cond_factory,
        filter            TYPE REF TO if_sadl_simple_cond_element,

  IF iv_element <> '<cds_view_name>'.
      RAISE EXCEPTION TYPE ...
  ENDIF.

 condition_manager = cl_sadl_cond_prov_factory_pub=>create_simple_cond_factory( ).
 filter->element('FIELD' ).

 CASE iv_operator.
  WHEN if_sadl_exit_filter_transform~co_operator-equals( ... ).
   ...
  WHEN if_sadl_exit_filter_transform~co_operator-less_than( ... ).
   ...
  WHEN if_sadl_exit_filter_transform~co_operator-greater_than( ... ).
   ro_condition = filter->greater_than( <parameter> ).
  WHEN OTHERS.
   RAISE EXCEPTION TYPE cx_sadl_exit_filter_not_supp.
  ENDCASE.
 ENDMETHOD.
ENDCLASS.

This is a wiki created in the spare time of a private person working in the SAP ERP area. The aim is to collect knowledge for the own use. The wiki is maintained to the best of knowledge and belief.
All products shown, including in form of screenshots, belong to SAP SE. Their trademarks are, among others: SAP®,ABAP®,SAP Fiori®,SAP HANA®,SAP NetWeaver®,SAP® R/3®,SAP S/4HANA®,SAP S/4HANA® Cloud