Skip to Content
Technical Articles

Predefined Virtual Data Model as example for understanding difference of CDS View type

Updated:

01/12/2018: Added CDS View including BOPF object and CDS View including Virtual Elements.

12/12/2018: Master View for value help in CDS View with UI annotation is added, and the CDS View with UI annotation in which value help master view is set cannot be set as Analytic Query.

 

Purpose of this blog

The first purpose of the blog is to provide an overview of CDS View and explain the differences between the CDS View types. There are many types of CDS Views, and characteristics and the definition are quite different. Some are positioned as data layer (transaction/master) and others are positioned as application objects and consumed by applications. I personally think Consumption View (CDS View used by application) cannot be called “View” (combination of tables/views) but should be rather “Query”.

There are Master CDS Views, Transaction CDS Views, CDS Views published as OData Services, CDS Views with UI annotation and Analytic Query etc. In addition, CDS Views for data extraction and  CDS API Views are available.

The second purpose of this blog is to provide example source code  for each of the CDS View types from the Predefined Virtual Data Model (VDM).

In addition, this blog also includes CDS View including table function, CDS View inclluding BOPF Object and CDS View including Virtual Elements for understanding the detail of the functions.

To understand the source code, I think the best way is to refer to the example source code, and it is also the case for ABAP CDS View. Other than Standard DEMO Examples of ABAP CDS views, you can see Predefined VDMs as examples to understand CDS Views. Unlike examples from DEMO CDS Views, you  see CDS Views based on the real business entities from Predefined VDMs. Simple examples for study may help, but sometimes the requirement in real world is more complex, so the samples  from a real case would be more helpful.

Please see the blog if you want to know the VDM used in a Fiori app.

My motivation to write this blog

CDS View is one of the key of S/4HANA architecture principles. Pushdown (execute within the HANA DB Engine) is included automatically when CDS Views  are used, and CDS Views are the foundation of Fiori applications. However, CDS Views may not be so easy to understand. One reason is many of the published  documents focus only on particular types of CDS View, e.g. Many  documents about Fiori Development, focus only on CDS View with UI annotation, and  Analytic Query, details about Interface Views are not included. I feel a holistic view of CDS View is what is expected.  I also belive general SQL knowledge is not enough,   where knowledge applying to application specific settings are  also required,  including  SAP specific characteristics, e.g. association.

I’m writing  this blog to help  address the current situation, of missing a holistic view of CDS View, with all required insights available in one place.

 

 Blog Contents

Due to the inclusion of source code within the section “Detail of Predefined VDM Types”, this blog will appear somewhat lengthy. However this example code is only a copy from an S/4HANA system, for ease of reading, you may prefer to skip this code and refer the source code within your own S/4HANA system.

CDS View types overview

CDS View types:

 

    • Interface View: This view is the foundation for Consumption Views (Tech naming pattern: I_*). Master View and Transaction View are both of the type “interface”.
      • Transaction CDS View and Master CDS View are not official terms, but my own terms. I differentiate them as the purpose, structure and settings are different. I dear to differentiate Transaction CDS View and Master CDS View because I believe it helps understanding better. Profit Center is obviously master data, and it is clear that Purchase Order is transaction data from semantic point of view, and technically characteristics of master view and transaction view are quite different in practice. In some cases, whether it is Transaction or Master is unclear, e.g. Billing document is obviously transactional entity but I_BillingDocumentItem might not be called so, as it does not have measures. But it is only exceptional case, and what is transaction and what is master is obvious in most cases.
    • Consumption View: The view consumed by applications (Tech naming pattern: C_*). Various Consumptrion View types are available depending on the application consuming the view, these include, CDS View published as OData Service, CDS View with UI Annotation, Analytic Query and CDS API View.
      • They are not official categories  other than CDS API View, but I differentiate them as the application to use them and settings are different.

  • Other important Predefined CDS View: This blog includes other important views worth highlighting.
    • CDS View as ODP Datasource can be used as a source to send the data to BW or other external system. Most of them are Interface View.
    • Table Function is also important to realize complex requirements.
    • For read/write application, CDS View including BOPF object is used.
    • For including ABAP logic in CDS View, Virtual Elements can be used (only for OData Service).
  • Private View is a view used as a part for Interface View and Consumption View, not supposed to be reused. There are 2 types in Interface View, Basic View and Composite View. Basic View is the view for an entity in S/4HANA and Consumption View consists of Basic View. This blog does not focus on those views as Private View and difference between Basic View and Composite View is not so important.

 

CDS View types and examples in this blog

1. Interface View

1.1. Master CDS View:I_Currency/I_ProfitCenter

1.2. Transaction CDS View: I_BillingDocumentItemCube

 

2. Consumption View:

2.1. CDS View published as OData Service: C_APFlexibleAging

2.2. CDS View with UI Annotation: C_SuplrEvalRspEvaluateST

2.3. Analytic Query: C_Trialbalanceq0001

2.4. CDS API View: A_BankDetail

 

3. Other important Predefined CDS Views

3.1. CDS View as ODP Datasource: I_BillingDocumentItem

3.2. CDS View including table function: P_SalesDocumentByMultObjSts

3.3. CDS View including BOPF object: I_SalesPlanTP

3.4. CDS View including Virtual Elements: C_Product

 

From the term “View”, you would imagine it is the combination of tables/views. However, in reality a Consumption View is rather a query or frontend object.

For those who may have some BW skills, we can compare some CDS Views to BW objects as follows:

Master CDS View is like an InfoObject (Charactersitic)

Transaction CDS View is like an InfoProvider (Transaction Basic View is like Infocube or ADSO

Transaction Composite View is like a Multiprovider or Composite Provider)

Consumption View is like a BW Query.

How to open CDS View in ADT

You can open the definition of the Predefined VDMs used in this blog with ADT as follows:

In ADT, Click “Open ABAP Development Object”.

Search with the DDL Source name (“I_PROFITCENTER” in the following case) and select the listed CDS View.

The definition of the CDS View is displayed.

Detail of CDS View types

1. Interface View

1.1 Master CDS View

  • In general, the source of a Master CDS View is an attribute table of the master data, text and hierarchy views, where the Master CDS View for each the attributes are associated.
  • In general, Analytic Data category is set as DIMENSION using the annotation “@Analytics.dataCategory”,   with the representative key  set using the annotation “@ObjectModel.representativeKey”.

A. Simple example: Currency code (I_Currency)

  • CDS View for Currency code (I_Currency) uses table TCURC and TCURX as a source which includes attribute data.
  • For Text data, I_CurrencyText is associated to the attribute and set as foreign key association using the annotation “@ObjectModel.text.association”.
  • Data Category is set as #DIMENSION.

 

I_Currency

@EndUserText.label: ‘Currency’

@ObjectModel.representativeKey: ‘Currency’

@ClientDependent: true

@Analytics: {dataCategory: #DIMENSION, dataExtraction.enabled: true}

@VDM.viewType: #BASIC

@AbapCatalog.sqlViewName: ‘IFICURRENCY’

@AccessControl.authorizationCheck: #NOT_REQUIRED

@Search.searchable: true

 

define view I_Currency

as select from tcurc

left outer join tcurx on tcurc.waers = tcurx.currkey

 

  association [0..*] to I_CurrencyText as _Text

    on $projection.Currency = _Text.Currency

{

 

@Semantics.currencyCode: true

@ObjectModel.text.association: ‘_Text’

key tcurc.waers as Currency,

_Text,

 

cast(COALESCE(tcurx.currdec, 2) as currdec) as Decimals,

 

@Search.defaultSearchElement: true

@Search.ranking: #HIGH

@Search.fuzzinessThreshold: 0.8

tcurc.isocd as CurrencyISOCode,

 

tcurc.altwr    as AlternativeCurrencyKey,

tcurc.xprimary as IsPrimaryCurrencyForISOCrcy

 

};

 

I_CurrencyText

  • Source is the text table of currency: TCURT
  • It has language key to which I_Language is associated.
  • Text field CurrencyName is set as text field using annotation “@Semantics.text”.
  • Object data category is set to #TEXT
@EndUserText.label: ‘Currency Text’
@ObjectModel.dataCategory: #TEXT
@ObjectModel.representativeKey: ‘Currency’
@Analytics.dataExtraction.enabled: true
@VDM.viewType: #BASIC
@AbapCatalog.sqlViewName: ‘IFICurrencyText’
@AccessControl.authorizationCheck: #NOT_REQUIREDdefine view I_CurrencyText
as select from tcurtassociation[1..1] to I_Currency as _Currency
on $projection.Currency = _Currency.Currency
association[0..1] to I_Language as _Language
on $projection.Language = _Language.Language
{
@Semantics.language: true
@ObjectModel.foreignKey.association: ‘_Language’
key spras as Language,
_Language,@Semantics.currencyCode: true
@ObjectModel.foreignKey.association: ‘_Currency’
key waers as Currency,
_Currency,@Semantics.text: true
ltext as CurrencyName,@Semantics.text: true
ktext as CurrencyShortName};   

 

B. Complex example: Profit Center (I_ProfitCenter)

I_ProfitCenter

  • CDS View for Profit Center (I_ProfitCenter) uses table CEPC as a source which includes attribute data
  • For Text data, I_ProfitCenterText is associated to the attribute and set as foreign key association.
  • For hierarchy data, I_ProfitCenterHierarchyNode is associated and set as hierarchy association using annotation “@ObjectModel.Hierarchy.association”.
  • For attributes, master view for them are associated to provide text and attributes of the attributes.

 

@EndUserText.label: ‘Profit Center’

@Analytics: { dataCategory: #DIMENSION, dataExtraction.enabled: true }

@VDM.viewType: #BASIC

@AbapCatalog.sqlViewName: ‘IFIPROFITCENTER’

@AccessControl.authorizationCheck: #CHECK

@AccessControl.privilegedAssociations:  [ ‘_ProfitCenterHierarchyNode’

//–[ GENERATED:012:29JlHNUf7jY4ipE4XHfNBG

,’_ControllingAreaText’,’_SegmentText’

// ]–GENERATED

]

@ObjectModel.representativeKey: ‘ProfitCenter’

@ClientHandling.algorithm: #SESSION_VARIABLE

@ObjectModel.usageType: {

dataClass: #MASTER,

serviceQuality: #A,

sizeCategory: #M

}

@Search.searchable: true

define view I_ProfitCenter  as select distinct from cepc

 

 

//–[ GENERATED:012:29JlHNUf7jY4ipE4XHfNBG

association [1..1] to I_ControllingArea      as _ControllingAreaText on   $projection.ControllingArea = _ControllingAreaText.ControllingArea

association [0..*] to I_SegmentText      as _SegmentText on   $projection.Segment = _SegmentText.Segment

// ]–GENERATED

association[1..1] to I_ControllingArea           as _ControllingArea           on $projection.ControllingArea   = _ControllingArea.ControllingArea

association[0..*] to I_ProfitCenterText          as _Text                      on $projection.ControllingArea   = _Text.ControllingArea and

$projection.ProfitCenter      = _Text.ProfitCenter and

$projection.ValidityEndDate   = _Text.ValidityEndDate

association[0..*] to I_ProfitCenterHierarchyNode as _ProfitCenterHierarchyNode on $projection.ControllingArea   = _ProfitCenterHierarchyNode.ControllingArea and

$projection.ProfitCenter      = _ProfitCenterHierarchyNode.ProfitCenter

association[0..1] to I_Country                   as _Country                   on $projection.Country           = _Country.Country

association[0..1] to I_CompanyCode               as _Company                   on $projection.CompanyCode       = _Company.CompanyCode

association[0..1] to I_Segment                   as _Segment                   on $projection.Segment           = _Segment.Segment

association[0..1] to I_Region                    as _Region                    on $projection.Country           = _Region.Country and

$projection.Region            = _Region.Region

//association[0..*] to I_TaxJurisdiction           as _TaxJurisdiction           on $projection.TaxJurisdiction   = _TaxJurisdiction.TaxJurisdiction

association[0..1] to I_Language                  as _Language                  on $projection.Language = _Language.Language

association[1..1] to E_ProfitCenter               as _Extension               on  $projection.ControllingArea    = _Extension.ControllingArea

and  $projection.ProfitCenter      = _Extension.ProfitCenter

and  $projection.ValidityEndDate   = _Extension.ValidityEndDate

 

{

//–[ GENERATED:012:29JlHNUf7jY4ipE4XHfNBG

@Consumption.valueHelpDefinition: [

{ entity:  { name:    ‘I_ControllingArea’,

element: ‘ControllingArea’ }

}]

@ObjectModel.text.association: ‘_ControllingAreaText’

// ]–GENERATED

@ObjectModel.foreignKey.association: ‘_ControllingArea’

key kokrs  as ControllingArea,

@ObjectModel.text.association: ‘_Text’

@ObjectModel.Hierarchy.association: ‘_ProfitCenterHierarchyNode’

@Search.defaultSearchElement: true

@Search.fuzzinessThreshold: 0.8

key prctr  as ProfitCenter,

 

@Semantics.businessDate.to: true

key datbi  as      ValidityEndDate,

verak as          ProfitCtrResponsiblePersonName,

bukrs as          CompanyCode,

verak_user as     ProfitCtrResponsibleUser,

@Semantics.businessDate.from: true

datab as          ValidityStartDate,

abtei as          Department,

khinr as          ProfitCenterStandardHierarchy,

//–[ GENERATED:012:29JlHNUf7jY4ipE4XHfNBG

@Consumption.valueHelpDefinition: [

{ entity:  { name:    ‘I_SegmentStdVH’,

element: ‘Segment’ }

}]

@ObjectModel.text.association: ‘_SegmentText’

// ]–GENERATED

@ObjectModel.foreignKey.association: ‘_Segment’ //Inserted by VDM CDS Suite Plugin

segment as        Segment,

lock_ind as       ProfitCenterIsBlocked,

pca_template as   FormulaPlanningTemplate,

anred as          FormOfAddress,

name1 as          AddressName,

name2 as          AdditionalName,

name3 as          ProfitCenterAddrName3,

name4 as          ProfitCenterAddrName4,

stras as          StreetAddressName,

pfach as          POBox,

ort01 as          CityName,

pstlz as          PostalCode,

ort02 as          District,

@ObjectModel.foreignKey.association: ‘_Country’ //Inserted by VDM CDS Suite Plugin

land1 as          Country,

@ObjectModel.foreignKey.association: ‘_Region’

regio as          Region,

txjcd as          TaxJurisdiction,

@Semantics.language:true

@ObjectModel.foreignKey.association: ‘_Language’ //Inserted by VDM CDS Suite Plugin

spras as          Language,

telf1 as          PhoneNumber1,

telf2 as          PhoneNumber2,

telbx as          TeleboxNumber,

telx1 as          TelexNumber,

telfx as          FaxNumber,

datlt as          DataCommunicationPhoneNumber,

drnam as          ProfitCenterPrinterName,

usnam as          ProfitCenterCreatedByUser,

ersda as          ProfitCenterCreationDate,

 

_Text,

_Country,

_ControllingArea,

_ProfitCenterHierarchyNode,

_Language,

_Company,

_Segment,

_Region,

//–[ GENERATED:012:29JlHNUf7jY4ipE4XHfNBG

@Consumption.hidden: true

_ControllingAreaText,

@Consumption.hidden: true

_SegmentText

// ]–GENERATED

 

//_TaxJurisdiction

}

 

C. Value help  

Other than the Master View in which analytical category is set to DIMENSION, there is Master View for Value help used in CDS View with UI annotation. As is used in the Value help for the transaction CDS View C_SUPLREVALRSPEVALUATEST, which is the source of Fiori app “Evaluate Suppliers “F1650”, Searchc annotation is used to activate fuzzy search in the value help of the selection field in the List Report.

Example: I_PurchasingCategoryValueHelp

@AbapCatalog.sqlViewName: ‘IPUCVH’
@EndUserText.label: ‘Purchasing Category’
@ObjectModel.representativeKey: ‘PurchasingCategory’@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #CHECK
@ClientHandling.algorithm: #SESSION_VARIABLE
@VDM.viewType: #COMPOSITE
@Search.searchable: true
@ObjectModel.usageType.serviceQuality: #C
@ObjectModel.usageType.sizeCategory: #M
@ObjectModel.usageType.dataClass: #MIXED

define view I_PurchasingCategoryValueHelp
as select distinct from I_PurchasingCategory
{
@Search.defaultSearchElement: true
@Search.ranking: #HIGH
@Search.fuzzinessThreshold: 0.5
@ObjectModel.text.element: ‘PurgCatName’
@Consumption.filter.hidden: true
key cast(I_PurchasingCategory.PurchasingCategory as /srmsmc/generic_id) as PurchasingCategory,

@Search.defaultSearchElement: true
@Semantics.text: true
@Search.ranking: #HIGH
@Search.fuzzinessThreshold: 0.5
@Consumption.filter.hidden: true
cast(I_PurchasingCategory.PurgCatName as /srmsmc/medium_name) as PurgCatName,

@Search.defaultSearchElement: true
@Semantics.text: true
@Search.ranking: #HIGH
@Search.fuzzinessThreshold: 0.5
@Consumption.filter.hidden: true
cast(I_PurchasingCategory._PurchasingCategoryDesc[1: Language = $session.system_language].PurgCatDescription as /srmsmc/description_medium) as PurgCatDescription
}

 

 

1.2. Transaction CDS View

Transaction CDS View is the foundation for the CDS View for applications. In the view, Master CDS Views are associated to attributes and the fields for measure are set as measure using annotation “@DefaultAggregation”. To be the foundation for the analytic query, it must be set as DIMENSION or CUBE in the annotation of Analytic Data category.

In Predefined VDM, in most Transaction Views, several Transaction View are created to create the one for the foundation of Consumption View. In the following case, I_BIllingDocumentItemCube is the source of Analytic Query C_SalesVolumeAnalysisQuery. I_BIllingDocumentItemCube is not created directly from VBRP but several Transaction CDS Views are created between the source transaction table and the Transaction View for Consumption View. But it is not mandatory to create several “nested” Transaction CDS Views.

 

Sample: I_BillingDocumentItemCube

  • Analytic Data Category is set to CUBE (or DIMENSION for some other Transaction CDS View) In this case, representative Key doesn’t have to be set. Then Analytic Query can be created on top of this view.
  • Master Data CDS Views are joined using association, and it is set as foreign key association with @ObjectModel.foreignKey.association, e.g. I_Product is associated and renamed to _Product, which is exposed (_Product is added in the selection field) and set to foreign key association to the field Product.
  • Fields for measure are set to be measure by using @DefaultAggregation and unit is associated.

@ClientHandling.algorithm: #SESSION_VARIABLE

@ObjectModel.usageType.dataClass: #MIXED

@ObjectModel.usageType.serviceQuality: #D

@ObjectModel.usageType.sizeCategory: #XL

@EndUserText.label: ‘Analytics – Sales Volume Cube’

@Analytics.dataCategory: #CUBE

@VDM.viewType: #COMPOSITE

@AccessControl.authorizationCheck:#CHECK

@AbapCatalog.sqlViewName: ‘ISDBILLGDOCITMC’

 

define view I_BillingDocumentItemCube

with parameters

P_ExchangeRateType : kurst,

P_DisplayCurrency  : vdm_v_display_currency

as select from I_BillingDocItemAnalytics as Item

left outer to one join I_SDDocStandardPartner     as HeaderPartner

on Item.BillingDocument = HeaderPartner.SDDocument

left outer to one join I_SDDocItemStandardPartner as ItemPartner

on  Item.BillingDocument = ItemPartner.SDDocument and Item.BillingDocumentItemInPartSgmt = ItemPartner.SDDocumentItem

left outer to one join I_CalendarDate as CalendarDate

on Item.CreationDate = CalendarDate.CalendarDate

left outer to one join I_CalendarDate as CalendarDateBillingDoc

on Item.BillingDocumentDate = CalendarDateBillingDoc.CalendarDate

left outer to one join I_EngagementProjectItem as CustomerProjectItem

on  Item.SalesDocument = CustomerProjectItem.EngagementProjectItem and CustomerProjectItem.EngagementProjectItemType = ‘0SOH’

association [0..1] to I_EngagementProject as _CustomerProject

on $projection.CustomerProject = _CustomerProject.EngagementProject

association [0..1] to I_Customer as _Customer

on $projection.Customer = _Customer.Customer

association [0..1] to I_Customer as _ShipToParty

on $projection.ShipToParty = _ShipToParty.Customer

association [0..1] to I_Customer as _BillToParty

on $projection.BillToParty = _BillToParty.Customer

association [0..1] to I_Employee as _SalesEmployee

on $projection.SalesEmployee = _SalesEmployee.PersonnelNumber

association [0..1] to I_Employee as _ResponsibleEmployee

on $projection.ResponsibleEmployee = _ResponsibleEmployee.PersonnelNumber

//Extension Association

association[0..1] to E_Billingdocumentitem as _Extension

on $projection.BillingDocument = _Extension.BillingDocument and $projection.BillingDocumentItem = _Extension.BillingDocumentItem

{

// Key

@ObjectModel.foreignKey.association: ‘_BillingDocument’

key BillingDocument,

key BillingDocumentItem,

 

// Key Association

_BillingDocument,

 

// Category

  @ObjectModel.foreignKey.association: ‘_SDDocumentCategory’

SDDocumentCategory,

  @ObjectModel.foreignKey.association: ‘_BillingDocumentCategory’

BillingDocumentCategory,

(omitted)

// Accounting

_CompanyCode,

_CustomerAccountAssgmtGroup,

_ExchangeRateType,

_DunningArea,

_DunningBlockingReason,

(omitted)

// Accounting

_CompanyCode,

_CustomerAccountAssgmtGroup,

(omitted)

// Analytics KPI

@Semantics.currencyCode: true

@ObjectModel.foreignKey.association: ‘_StatisticsCurrency’

  StatisticsCurrency,

_StatisticsCurrency,

 

@DefaultAggregation: #SUM

@Semantics.amount.currencyCode: ‘TransactionCurrency’

SalesVolumeNetAmount,

@DefaultAggregation: #SUM

@Semantics.amount.currencyCode: ‘DisplayCurrency’

cast ( currency_conversion(

amount => SalesVolumeNetAmount,

source_currency => TransactionCurrency,

target_currency => :P_DisplayCurrency,

exchange_rate_date => BillingDocumentDate,

exchange_rate_type => :P_ExchangeRateType,

error_handling => ‘FAIL_ON_ERROR’,

round => #CDSBoolean.true,

decimal_shift => #CDSBoolean.true,

decimal_shift_back => #CDSBoolean.true

) as mc_umnetwr ) as SlsVolumeNetAmtInDspCrcy,

..

(omitted)…

In the transaction view used as the source of OData based Consumption views, keys have to be set.

 

2. Consumption View

2.1. CDS View published as OData Service

  • The CDS View published as OData Service can be used in Smart Business Apps including KPI tile,  Analytical List Report (created with Fiori Report Design Modeler app) and Analysis Path Framework (APF).
  • The field to which exposed master view should be associated or to which text field is associated using @ObjectModel.text.element (e.g. C_BankRiskAnalytics) to group Key and text, which can be used in Smart Business apps. But it is not mandatory.
  • For measure field, aggregation type have to be defind using @DefaultAggregation.
  • Other settings like “parameters” or “where conditions” can be included. In many of the SAP standard CDS Views for KPI Tiles, the parameter P_DateFunction is included with which the date or period can be filtered dynamically, e.g. C_OverduePO. See the blog for further details.
  • It is possible to create “calculated measures” with the AnalyticsDetail annotation (e.g. @AnalyticsDetails.query.formula: ‘NETWR – WAVWR ‘) for this view type. To do this , the view needs be set to Analytic Query (see below).
  • It is not mandatory to create from Interface view, but it is enough to be published as OData Service. It is technically no problem to include the settings normally in the Interface view, e.g. association, default aggregation, associating unit to measure in this view. Example of this type is C_PurOrdValueWithPlnd. In this case, keys have to be set in the Interface View.

 

Example: C_APFlexibleAging (Used in Fiori App “Aging Analysis” (F1733))

@EndUserText.label: ‘Aging Analysis’

@VDM.viewType: #CONSUMPTION

@Analytics.query: true

@OData.publish: true

@AbapCatalog.sqlViewName: ‘CAPFLXBLAGING’

@AccessControl.authorizationCheck: #PRIVILEGED_ONLY

@ClientHandling.algorithm: #SESSION_VARIABLE

@ObjectModel.usageType.serviceQuality: #D

@ObjectModel.usageType.sizeCategory: #XXL

@ObjectModel.usageType.dataClass: #MIXED

@Metadata.ignorePropagatedAnnotations: true

define view C_APFlexibleAging

// Corresponds to calculation view ‘sap.hba.r.sfin700.AccountsPayableFlexibleAgingQuery’

with parameters

    @EndUserText.label: ‘Open on Key Date’

    @Consumption.defaultValue: ‘TODAY’

    @Consumption.valueHelpDefinition: [{

      entity: {

        name: ‘C_GregorianCalSglDateFuncVH’,

        element: ‘DateFunction’

      }

    }]

    P_DateFunction : datefunctionid,

   

    @Consumption.derivation: {

      lookupEntity: ‘I_SglGregorianCalDateFunction’,

      resultElement: ‘DateFunctionStartDate’,

      binding: [

        { targetParameter : ‘P_DateFunction’ ,

          type : #PARAMETER, value : ‘P_DateFunction’ }

      ]

    }

    @Consumption.hidden: true

    P_KeyDate : sydate,

   

    @Consumption.hidden: true

    @Environment.systemField: #SYSTEM_LANGUAGE

    P_Language : sylangu,

   

    @Consumption.defaultValue: ’15’

    P_AgingGridMeasureInDays : farp_aging_grid_measure,

 

    @Consumption.defaultValue: ‘4’

    P_NumberOfAgingGridColumns : farp_number_of_grid_columns,

   

    @Consumption.defaultValue: ‘EUR’   

    P_DisplayCurrency : vdm_v_display_currency

 

as select from

I_APFlexibleAging(

P_KeyDate : :P_KeyDate,

P_AgingGridMeasureInDays : :P_AgingGridMeasureInDays,

P_NumberOfAgingGridColumns : :P_NumberOfAgingGridColumns,

P_DisplayCurrency : :P_DisplayCurrency)

{

key CompanyCode,

key TransactionCurrency,

key GLAccount,

key Supplier,

//key PaymentTerms,

key AccountingDocumentCategory,

key AgingGridText,

 

_CompanyCode.CompanyCodeName as CompanyCodeName ,

_GLAccount._Text[1:Language = $parameters.P_Language].GLAccountLongName as GLAccountLongName,

_Supplier.SupplierName as SupplierName,

_AccountingDocumentCategory._Text[1:Language = $parameters.P_Language].AccountingDocumentCategoryName,

 

ChartOfAccounts,

_ChartOfAccounts._Text[1:Language = $parameters.P_Language].ChartOfAccountsName,

SupplierAccountGroup,

_SupplierAccountGroup._SupplierAccountGroupText[1:Language = $parameters.P_Language].AccountGroupName as SupplierAccountGroupName,

 

@Semantics.currencyCode:true

DisplayCurrency,

 

@DefaultAggregation: #SUM

@Semantics.amount.currencyCode: ‘DisplayCurrency’

AmountInDisplayCurrency_E,

 

@DefaultAggregation: #SUM

@Semantics.amount.currencyCode: ‘DisplayCurrency’

TotalNotOvrdAmtInDspCrcy,

 

@DefaultAggregation: #SUM

@Semantics.amount.currencyCode: ‘DisplayCurrency’

TotalOverdueAmtInDspCrcy_E

 

};

 

2.2. CDS View with UI Annotation

  • CDS View with UI Annotation can be used in Fiori Elements apps including List Report, Analytical List Page(ALP)/Object Page, Overview Page, Worklist/Object Page.
  • UI Annotations are included to define the UI setting of the Fiori Elements apps, e.g. OData Publish, @UI.lineItem is used for displaying the field in the initial screen, @UI.selectionField is used to set the field to be included in the selection field area in the initial screen.
    • It is not mandatory to include UI Annotation, but Settings for UI is possible using a Local Annotation with Annotation Modeler in Fiori Elements template in Web IDE. Please watch the movie for further details. This means, “CDS View published as OData Service” can also be the source of Fiori Elements apps.
  • It is possible to create “calculated measures” with AnalyticsDetail annotation (e.g. @AnalyticsDetails.query.formula: ‘NETWR – WAVWR ‘) for this view type. To enable this, the view needs to be set to Analytic Query (see below), but in this case, associated Master View cannot be used as the value help in List Report. Example in which associated master view is used for value help in List Report is C_SuplrEvalRspEvaluateST, which is the source of Fiori app “Evaluate Suppliers” (F1650).
  • Search Annotation can be included to make freestyle search available.
  • Other settings like “parameters” or “where conditions” can be included. (But Parameter cannot be used in List Report by default)
  • It is not mandatory to create this view type from an Interface view, it is sufficient to be published as OData Service (the same as CDS View published as OData Service).

 

Example:C_CnsldtnJrnlEntr (Used in Fiori App “Display Group Journal Entries” (F2573)

@AbapCatalog.sqlViewName: ‘CCNSLDTNJRNLENTR’

@AbapCatalog.compiler.compareFilter: true

@AccessControl.authorizationCheck: #NOT_ALLOWED

@EndUserText.label: ‘Journal Entry Comsumption View’

@VDM.viewType: #CONSUMPTION

@ObjectModel.compositionRoot:true

@ClientHandling.algorithm: #SESSION_VARIABLE

@ObjectModel.usageType: {

sizeCategory: #XXL,

serviceQuality: #D,

dataClass: #MIXED

}

 

@OData.publish: true

@UI.headerInfo: {

  typeName: ‘Journal Entry’,

  typeNamePlural: ‘Journal Entries’,

  title: {

    label: ‘Accounting Document Number’,

    value: ‘CnsldtnDocumentNumber’

  },

  description: {

    label: ‘Accounting Document Text’,

    value: ‘CnsldtnItemText’

  }

}

 

@UI.presentationVariant.requestAtLeast:  [ ‘CnsldtnRecordNumber’, ‘CnsldtnDimension’ ]

 

define view C_CnsldtnJrnlEntr

as select from I_CnsldtnJrnlEntr

association [0..*] to C_CnsldtnJrnlEntrItem as _Item on $projection.CnsldtnRecordNumber = _Item.CnsldtnRecordNumber

{

 

//@UI.lineItem: [{position:200,importance: #LOW}]

//@UI.hidden: true

key CnsldtnRecordNumber,

 

//Document Number

      @UI.lineItem.position: 10

CnsldtnDocumentNumber,

 

//Document Number line item

     @UI.lineItem: [{position:20,importance: #HIGH}]

CnsldtnPostingItem,

 

//Period e.g. 012 / 2016

@UI.lineItem: [{position:30,importance: #HIGH}]

      @UI.selectionField.position:20

      @UI.fieldGroup: [{qualifier:’FiscalPeriod’, groupLabel: ‘FiscalPeriod’, position: 10, importance: #HIGH}]

FiscalPeriod,

 

//Document Type

      @UI.lineItem: [{position:40,importance: #HIGH}]

      @UI.identification: {position: 10, importance: #HIGH}

CnsldtnDocumentType,

 

//Consolidation unit

      @UI.lineItem: [{position:50,importance: #HIGH}]

      @UI.selectionField.position:60

      @UI.identification: {position: 30, importance: #HIGH}

CnsldtnUnit,

 

//FS Item

     @UI.lineItem: [{position:60,importance: #HIGH}]

CnsldtnFinStmntItm,

 

//SubItem category

      @UI.lineItem: [{position:70,importance: #HIGH}]

      @UI.fieldGroup: [{qualifier:’UniqueSubAssignment’, groupLabel: ‘Unique Subassignments’, position: 10, importance: #HIGH}]

CnsldtnFinStmntSubItmCat,

 

(omitted)

//Amount in transaction currency

@DefaultAggregation: #SUM

@Semantics.amount.currencyCode: ‘TransactionCurrency’

      @UI.lineItem: [{position:110,importance: #HIGH}]

AmountInTransactionCurrency,

 

//Amount in local currency

@DefaultAggregation: #SUM

@Semantics.amount.currencyCode: ‘CnsldtnLocalCurrency’

      @UI.lineItem: [{position:120,importance: #HIGH}]

AmountInCnsldtnLocalCrcy,

 

(omitted)

 

2.3 Analytic Query

  • Analytic Query is a type of CDS View, which is exposed to the SAP HANA Analytical Engine so it can be used for multidimensional analytics, e.g. slicing, dicing and drilldown. It can be consumed just the same way as BW Queries, e.g. for testing with the BW transaction code RSRT, and for consumption via SAP Analysis for Office. It can be the source of Fiori Multidimensional Reporting app and SAP Analytics Cloud Online scenarios. It can also be used with BusinessObjects solution.
  • It is set as an Analytic Query with annotation @Analytics.query: true,
    • It needs to use the Interface View in which Analytic Data Category is set to #CUBE or #DIMENSION.
    • Association join cannot be set in an Analytic Query view.
    • Attributes of associated master view are ignored in Analytic Query views  (so the attributes of the associated master view  need to be set in the Interface view).
  • With AnalyticsDetails Annotations, default multidimensional layout of the query can be specified. The query must be set as Analytic Query (@Analytics.query: true). Restricted and Calculated Measure can be created.
    • When creating Calculated Measure with AnalyticsDetail Annotation, the Calculated Measure created in the same view can be used in the formula of another Calculated Measure. (e.g. @AnalyticsDetails.query.formula: ‘NETWR – WAVWR ‘ 1 as CM1, @AnalyticsDetails.query.formula: ‘ $projection.CM1/NETWR ’ 1 as CM12).
  • To define a specific behavior that relates to the consumption of CDS content through domain-specific frameworks, Consumption Annotations is used, e.g. to set an attribute as a prompt value, @Consumption.filter is used.
  • See Wiki page for more details relating to annotations in Analytic Query view.
  • Other settings like “parameters” or “where conditions”: can also be included.

 

Example: C_Trialbalanceq0001 (Used in Fiori App “Trial Balance” (F0996A))

@AbapCatalog.sqlViewName: ‘CFITRIALBALQ0001’

@EndUserText.label: ‘Trial Balance’

@VDM.viewType: #CONSUMPTION

@Analytics.query: true

@AccessControl.authorizationCheck: #PRIVILEGED_ONLY

@ClientHandling.algorithm: #SESSION_VARIABLE

@AbapCatalog.buffering.status: #NOT_ALLOWED

@Metadata.ignorePropagatedAnnotations: true

@ObjectModel.usageType.sizeCategory: #XXL

@ObjectModel.usageType.serviceQuality: #D

@ObjectModel.usageType.dataClass: #MIXED

 

define view C_Trialbalanceq0001

with parameters

@Consumption.hidden: true

@Environment.systemField: #SYSTEM_LANGUAGE

  P_Language        : sylangu,

@Consumption.hidden: true

@Environment.systemField: #SYSTEM_DATE

  P_KeyDate         : sydate,

 

@Consumption.derivation: { lookupEntity: ‘I_CalendarDate’,

    resultElement: ‘FirstDayofMonthDate’, binding: [

    { targetElement : ‘CalendarDate’ , type : #PARAMETER, value : ‘P_KeyDate’ } ]

   }   

  P_FromPostingDate : fis_budat_from,

 

@Consumption.derivation: { lookupEntity: ‘I_CalendarDate’,

    resultElement: ‘CalendarDate’, binding: [     

    { targetElement : ‘CalendarDate’ , type : #PARAMETER, value : ‘P_KeyDate’ } ]

   } 

  P_ToPostingDate   : fis_budat_to     

 

 

as select from I_GLAcctBalanceCube

( P_FromPostingDate: $parameters.P_FromPostingDate, P_ToPostingDate: $parameters.P_ToPostingDate )

 

{

 

// Filter/ Fixed Rows

@Consumption.filter: {selectionType: #SINGLE, multipleSelections: false, mandatory: true}

@Consumption.derivation: { lookupEntity: ‘I_LedgerStdVH’,

      resultElement: ‘Ledger’, binding: [

      { targetElement : ‘IsLeadingLedger’ , type : #CONSTANT, value : ‘X’ } ]

     }

@AnalyticsDetails.query.variableSequence : 10

//@AnalyticsDetails.query.axis: #FREE

Ledger,

 

@Consumption.filter: {selectionType: #RANGE, multipleSelections: true, mandatory: true}

@AnalyticsDetails.query.variableSequence : 20

@AnalyticsDetails.query.axis: #ROWS

@AnalyticsDetails.query.totals: #SHOW

CompanyCode,

_CompanyCode.CompanyCodeName,

 

(Omitted)

 

// Calculation of starting balance is done in the query for performance reasons

@AnalyticsDetails.query.axis: #COLUMNS

//@EndUserText.label: ‘Starting Balance CC’

@DefaultAggregation: #FORMULA

@Semantics.amount.currencyCode: ‘CompanyCodeCurrency’

@AnalyticsDetails.query.formula : ‘$projection.EndingBalanceAmtInCoCodeCrcy – $projection.DebitAmountInCoCodeCrcy – CreditAmountInCoCodeCrcy’

cast( cast( 1 as abap.dec(23,2)) as fis_start_bal_hsl_ui ) as StartingBalanceAmtInCoCodeCrcy,

 

 

// Debit and Credit Balance has an exception aggregation to make sure that LedgerFiscalYear is part of the select list

// this is necessary to push down the aggregation to the lowest level, since LedgerFiscalYear is part of the join condition of the FiscalCalenderDate

@AnalyticsDetails.query.axis: #COLUMNS

//@EndUserText.label: ‘Debit Balance CC’

@DefaultAggregation: #FORMULA

@Semantics.amount.currencyCode: ‘CompanyCodeCurrency’

@AnalyticsDetails: {

        exceptionAggregationSteps: [{ exceptionAggregationBehavior : #SUM,

                                      exceptionAggregationElements: [‘LedgerFiscalYear’]

                                   }]

    }

@AnalyticsDetails.query.formula : ‘$projection.GLAcctDebitAmtInCoCodeCrcy’ cast( cast( 1 as abap.dec(23,2)) as fis_dr_bal_hsl ) as DebitAmountInCoCodeCrcy, 

 

                                      exceptionAggregationElements: [‘FiscalPeriodDate’]

//                                      exceptionAggregationElements: [‘PostingDate’]

                                   }]

    }

@AnalyticsDetails.query.formula : ‘$projection.IntmdEndingBalAmtInCoCodeCrcy’ cast( cast( 1 as abap.dec(23,2)) as fis_end_bal_hsl_ui ) as EndingBalanceAmtInCoCodeCrcy, 

(Omitted)

 

2.4. CDS API View

  • CDS API View is supposed to be used as API.
  • It is not published as OData Service, and not set to Analytic Query.
  • Text field is not included.

 

Example: A_BankDetail

@AbapCatalog.sqlViewName: ‘ABKDET’

@EndUserText.label: ‘Remote API Contract for Bank Detail’

@VDM:{

viewType: #BASIC,

lifecycle.contract.type:#PUBLIC_REMOTE_API

}

 

@AccessControl.authorizationCheck: #CHECK

 

@ObjectModel: {

usageType: {

serviceQuality: #B,

sizeCategory:   #L,

dataClass:      #MASTER

}

}

@Metadata.ignorePropagatedAnnotations: true

@ClientHandling.algorithm: #SESSION_VARIABLE

@AbapCatalog.compiler.compareFilter: true

define view A_BankDetail as select from bnka {

 

key banks as BankCountry,

key bankl as BankInternalID,

banka as BankName,

swift as SWIFTCode,

bgrup as BankGroup,

bnklz as BankNumber,

provz as Region,

stras as StreetName,

ort01 as CityName,

brnch as Branch

 

//      xpgro as IsPostBankAccount,

//      loevm as IsMarkedForDeletion,

//      pskto as PostOfficeBankAccount,

//      chkme as CheckDigitCalculationMethod,

//      vers as BankDataFileFormat,

//      erdat as CreationDate ,

//      ernam as CreatedByUser,

//      adrnr as AddressID

}where loevm =or loevm = ‘ ‘;

 

3. Other important Predefined CDS Views

3.1. CDS View as ODP Data Source

  • The CDS View can be used as a data source to send the data to BW system. It is a kind of ODP Data Source. The CDS View can be set to ODP Data Source with the annotation @Analytics.dataExtraction.enabled: true.
  • In the BW system connected to S/4HANA system (including embedded BW in S/4HANA), the CDS View can be replicated as ODP Data Source. See the blog in detail. This data source can also be used by DataServices, SDI etc. in the same way as a BW Data Source.
  • Most of the CDS  Views as ODP Data Source are Interface View. In those Interface View, the annotation @Analytics.dataExtraction.enabled: true is included.

 

Example: I_BillingDocumentItem

@ClientHandling.algorithm: #SESSION_VARIABLE

@ObjectModel.usageType.dataClass: #TRANSACTIONAL

@ObjectModel.usageType.serviceQuality: #A

@ObjectModel.usageType.sizeCategory: #XL

@ObjectModel.representativeKey: ‘BillingDocumentItem’

@EndUserText.label: ‘Billing Document Item’

@Analytics: { dataCategory: #DIMENSION, dataExtraction.enabled: true }

@VDM.viewType: #BASIC

@AccessControl.authorizationCheck:#CHECK

@AbapCatalog.sqlViewName: ‘ISDBILLGDOCITEM’

 

define view I_BillingDocumentItem

 

as select from P_BillingDocumentItemBasic

association[1..1] to I_BillingDocument   as _BillingDocument          on $projection.BillingDocument          = _BillingDocument.BillingDocument

//Extension Association

association[1] to E_Billingdocumentitem as _Extension on $projection.BillingDocument = _Extension.BillingDocument and $projection.BillingDocumentItem = _Extension.BillingDocumentItem

{

//Key

@ObjectModel.foreignKey.association: ‘_BillingDocument’

key BillingDocument,

key BillingDocumentItem,

 

//Category

// VBTYP as SDDocumentCategory,

SalesDocumentItemCategory,

SalesDocumentItemType,

ReturnItemProcessingType,

 

//Admin

CreatedByUser,

CreationDate,

CreationTime,

LogicalSystem,

..

(Omitted)..

..

 

3.2. CDS View including Table Function

(This example is to explain the technical characteristics, which is slightly different from the main topic of this blog. But  as it is so interesting and think it will help provide further context the Predefined VDM).

Table function can be the source of a CDS View, and Native SQL can be included in it. By using flexibility of Native SQL, a more sophisticated process might be possible. In Table Function, ABAP Managed Database Procedure (AMDP) is included in which Native SQL can be included.

 

Example: P_SalesDocumentByMultObjSts

@ClientHandling.type: #CLIENT_DEPENDENT

@ClientHandling.algorithm: #SESSION_VARIABLE

@AccessControl.authorizationCheck: #NOT_REQUIRED

@VDM.viewType: #BASIC

@VDM.private: true

 

define table function P_SalesDocumentByMultObjSts

with parameters

im_clnt : abap.clnt @<Environment.systemField: #CLIENT

returns

{

key Client                : mandt;

key SalesDocument         : vbeln_va;

key SalesDocumentItem     : posnr;

 

// System Status long name concatenated, max. 100 for one Item

SystemStatusName      : concat_sys_status_name;

 

// System Status short name concatenated, max. 100 for one Item

SystemStatusShortName : concat_sys_status_short_name;

 

// User Status long name concatenated, max. 100 for one Item

UserStatusName        : concat_user_status_name;

 

// User Status short name concatenated, max. 100 for one Item

UserStatusShortName   : concat_user_status_short_name;

 

}

implemented by method

CL_SD_SLSDOCBYOBJSTS=>CONCAT_STATUS_FOR_SLSDOC;

 

In the Native SQL of the AMDP, “string_agg” is used, which is not available in normal ABAP CDS Views.

CLASS CL_SD_SLSDOCBYOBJSTS DEFINITION

PUBLIC

FINAL

CREATE PUBLIC .

 

PUBLIC SECTION.

 

INTERFACES IF_AMDP_MARKER_HDB .

 

CLASS-METHODS CONCAT_STATUS_FOR_SLSDOC

FOR TABLE FUNCTION P_SALESDOCUMENTBYMULTOBJSTS .

 

PROTECTED SECTION.

PRIVATE SECTION.

ENDCLASS.

 

 

 

CLASS CL_SD_SLSDOCBYOBJSTS IMPLEMENTATION.

 

 

METHOD CONCAT_STATUS_FOR_SLSDOC BY DATABASE FUNCTION FOR HDB LANGUAGE SQLSCRIPT OPTIONS READ-ONLY

USING PSLSDOCBYOBJSTS.

 

RETURN

SELECT “P1″.”MANDT”                                               AS Client,

“P1″.”SALESDOCUMENT”                                       AS SalesDocument,

“P1″.”SALESDOCUMENTITEM”                                   AS SalesDocumentItem,

 

string_agg ( concat(“P1″.”SYSTEMSTATUSNAME”, concat(‘ (‘, concat(“P1″.”SYSTEMSTATUSSHORTNAME”, ‘)\n’) ) ) )     AS SystemStatusName,

string_agg ( concat(“P1″.”SYSTEMSTATUSSHORTNAME”, ‘\n’) )  AS SystemStatusShortName,

 

string_agg ( concat(“P1″.”USERSTATUSNAME”, concat(‘ (‘, concat(“P1″.”USERSTATUSSHORTNAME”, ‘)\n’) ) ) )         AS UserStatusName,

string_agg ( concat(“P1″.”USERSTATUSSHORTNAME”, ‘\n’) )    AS UserStatusShortName

 

FROM “PSLSDOCBYOBJSTS” “P1”

GROUP BY “P1″.”MANDT”, “P1″.”SALESDOCUMENT”, “P1″.”SALESDOCUMENTITEM” ;

 

ENDMETHOD.

ENDCLASS.

 

Table function can be used in other CDS View.

P_SalesDocumentByMultObjSts is used in C_SalesDocumentByObjectStatus.

(omitted)

define view C_SalesDocumentByObjectStatus
as select from P_SalesDocumentByMultObjSts( im_clnt : $session.client )

association [0..1] to I_SalesDocument as _SalesDocument on $projection.SalesDocument = _SalesDocument.SalesDocument

(omitted)

 

 

3.3. CDS View including BOPF object

CDS View including BOPF Business Object works as the source of the apps to insert/update/delete data as well as to read.

There are many sources about BOPF like the blog.

On the other hand, BOPF is not a part of new framework called ABAP RESTful Programming Model (RAP).

Example: I_SalesPlanTP

(It is the source of C_SalesPlanTP used in OData SD_SALESPLAN, the OData of Fiori app “Manage Sales Plans”)

@EndUserText.label: ‘Sales Plan Header Transaction Object’
@VDM.viewType: #TRANSACTIONAL
@AccessControl.authorizationCheck: #NOT_REQUIRED
@AbapCatalog.sqlViewName: ‘ISDSLSPLANTP’@ClientHandling.algorithm: #SESSION_VARIABLE
@ObjectModel.usageType.dataClass: #TRANSACTIONAL
@ObjectModel.usageType.serviceQuality: #A
@ObjectModel.usageType.sizeCategory: #XL@ObjectModel.transactionalProcessingEnabled: true
@ObjectModel.draftEnabled: true
@ObjectModel.compositionRoot: true@ObjectModel.writeDraftPersistence: ‘SALESPLAN_D’
@ObjectModel.writeActivePersistence: ‘SALESPLAN’
@ObjectModel.entityChangeStateId: ‘LastChangeDateTime’@ObjectModel.createEnabled:true
@ObjectModel.updateEnabled: ‘EXTERNAL_CALCULATION’
@ObjectModel.deleteEnabled: ‘EXTERNAL_CALCULATION’@ObjectModel.semanticKey: [ ‘SalesPlan’ ]define view I_SalesPlanTP
as select from I_SalesPlan
association [0..*] to I_SalesPlanItemTP as _SalesPlanItem on $projection.SalesPlanUUID = _SalesPlanItem.SalesPlanUUID
association [0..*] to I_SalesPlanDimnSelectionTP as _SalesPlanDimnSelection on $projection.SalesPlanUUID = _SalesPlanDimnSelection.SalesPlanUUID
{
key SalesPlanUUID,
@ObjectModel: {
mandatory: true,
readOnly: ‘EXTERNAL_CALCULATION’
}
SalesPlan,
@ObjectModel.mandatory: true
SalesPlanVersion,@ObjectModel.readOnly: ‘EXTERNAL_CALCULATION’
SalesPlanDescription,
SalesPlanVersionDescription,
@ObjectModel.readOnly: true
SalesPlanStatus,@Semantics.currencyCode: true
@ObjectModel.mandatory: true
SalesPlanCurrency,@ObjectModel.readOnly: ‘EXTERNAL_CALCULATION’
SalesPlanPeriodType,
@ObjectModel: {
mandatory: ‘EXTERNAL_CALCULATION’, //Date type with mandatory true will cause exception
readOnly: ‘EXTERNAL_CALCULATION’
}
SalesPlanFrom,
…(omitted)

Object Model annotation is used for the detail setting for the CDS View with BOPF Business Object.

BOPF Business Object can be opend with ADT.

It can be checked with the Transaction BOB in SAPGUI.

 

3.4. CDS View including Virtual Elements

ABAP Logic can be included in CDS View using Virtual Element. It is defined at the level of CDS consumption views as additional elements within the SELECT list using specific @DataModel annotations. However, the calculation or further processing of their values is carried out by means of ABAP classes that implement the specific code exit interfaces provided for this purpose. This function is available as of NW 7.52.

It works only in the generated OData service, not in, e.g. Analytic Query.

Example: C_Product

(it is used in the OData MD_C_PRODUCT_MAINTAIN_SRV, the source of Fiori app “Manage Product Master”)

(omitted)

….

define view C_Product
as select from I_ProductWD as Product

(omitted)

….

@ObjectModel.readOnly: true
@ObjectModel.virtualElement
@ObjectModel.virtualElementCalculatedBy: ‘ABAP:CL_MD_PRODUCT_ROOT_CALC_EXIT1’
cast(” as ad_namtext) as LastChangedByUserName,

@ObjectModel.readOnly: true
@ObjectModel.virtualElement
@ObjectModel.virtualElementCalculatedBy: ‘ABAP:CL_MD_PRODUCT_ROOT_CALC_EXIT1’
cast(” as ad_namtext) as CreatedByUserName,

(omitted)

 

Class: CL_MD_PRODUCT_ROOT_CALC_EXIT1

CLASS cl_md_product_root_calc_exit1 DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .PUBLIC SECTION.INTERFACES if_sadl_exit .
INTERFACES if_sadl_exit_calc_element_read .
PROTECTED SECTION.
private section.constants:
BEGIN OF cs_calc_element,
productimageurl TYPE sadl_entity_element VALUE ‘PRODUCTIMAGEURL’,
createdbyusername TYPE sadl_entity_element VALUE ‘CREATEDBYUSERNAME’,
lastchangedbyusername TYPE sadl_entity_element VALUE ‘LASTCHANGEDBYUSERNAME’,
END OF cs_calc_element .
constants:
BEGIN OF cs_cal_element_variant,
variantenabled TYPE sadl_entity_element VALUE ‘VARIANTENABLED’,
END OF cs_cal_element_variant .methods GET_IMAGE_URL
importing
!IT_ORIGINAL_DATA type STANDARD TABLE
changing
!CT_CALC type STANDARD TABLE .
methods SET_FULL_NAME
importing
!IV_UNAME_TYPE type STRING
!IT_ORIGINAL_DATA type STANDARD TABLE
changing
!CT_CALC type STANDARD TABLE .
methods SET_VARAINTENABLED
importing
!IV_UNAME_TYPE type STRING
!IT_ORIGINAL_DATA type STANDARD TABLE
changing
!CT_CALC type STANDARD TABLE .
ENDCLASS.CLASS CL_MD_PRODUCT_ROOT_CALC_EXIT1 IMPLEMENTATION.METHOD get_image_url.DATA: lv_object_key TYPE objky,
lv_mimetype TYPE w3conttype,
lv_thumbnail_url TYPE saeuri.FIELD-SYMBOLS: <fs_calc> TYPE any,
<fs_isactive> TYPE simple,
<fs_product> TYPE simple.MOVE-CORRESPONDING it_original_data TO ct_calc.
LOOP AT ct_calc ASSIGNING <fs_calc>.
ASSIGN (‘<fs_calc>-PRODUCTIMAGEURL’) TO FIELD-SYMBOL(<fs_imageurl>).
CHECK sy-subrc = 0.
ASSIGN (‘<fs_calc>-ISACTIVEENTITY’) TO <fs_isactive>.
CHECK sy-subrc = 0.
IF <fs_isactive> EQ abap_true.
ASSIGN (‘<fs_calc>-PRODUCT’) TO <fs_product>.
CHECK sy-subrc = 0.lv_object_key = <fs_product>.
cl_document_thumbnail_api=>get_instance( )->get_document_thumbnail(
EXPORTING iv_objecttype = ‘MARA’
iv_objectkey = lv_object_key
* is_dir_key =
iv_get_url_only = abap_true
IMPORTING ev_mimetype = lv_mimetype
ev_thumbnail_url = lv_thumbnail_url ).
IF lv_thumbnail_url IS NOT INITIAL.
<fs_imageurl> = lv_thumbnail_url.
ENDIF.
ENDIF.
IF <fs_imageurl> IS INITIAL.
<fs_imageurl> = ‘/sap/bc/ui5_ui5/sap/MD_PROD_MAS_S1/images/Icn.png’.
ENDIF.
ENDLOOP.ENDMETHOD.METHOD if_sadl_exit_calc_element_read~calculate.TYPES:
BEGIN OF ty_calc,
productimageurl TYPE c_product-productimageurl,
product TYPE c_product-product,
productforedit TYPE c_product-productforedit,
isactiveentity TYPE boolean,
createdbyuser TYPE c_product-createdbyuser,
createdbyusername TYPE c_product-createdbyusername,
lastchangedbyuser TYPE c_product-lastchangedbyuser,
lastchangedbyusername TYPE c_product-lastchangedbyusername,
END OF ty_calc.
TYPES :
BEGIN OF ty_calc_variant,
product TYPE c_productvariantmatrix-product,
productforedit TYPE c_productvariantmatrix-productforedit,
variantenabled TYPE c_productvariantmatrix-variantenabled,
END OF ty_calc_variant.DATA: lt_calc TYPE STANDARD TABLE OF ty_calc,
lt_calc_variant TYPE STANDARD TABLE OF ty_calc_variant,
lv_object_key TYPE objky,
lv_mimetype TYPE w3conttype,
lv_thumbnail_url TYPE saeuri.FIELD-SYMBOLS: <fs_calc> TYPE any,
<fs_isactive> TYPE simple,
<fs_product> TYPE simple.CHECK NOT it_original_data IS INITIAL.IF line_exists( it_requested_calc_elements[ table_line = cs_calc_element-productimageurl ] ).CALL METHOD get_image_url
EXPORTING
it_original_data = it_original_data
CHANGING
ct_calc = lt_calc.
ENDIF.
IF line_exists( it_requested_calc_elements[ table_line = cs_calc_element-lastchangedbyusername ] ).CALL METHOD set_full_name
EXPORTING
iv_uname_type = ‘CHANGEDBY’
it_original_data = it_original_data
CHANGING
ct_calc = lt_calc.
ENDIF.
IF line_exists( it_requested_calc_elements[ table_line = cs_calc_element-createdbyusername ] ).

CALL METHOD set_full_name
EXPORTING
iv_uname_type = ‘CREATEDBY’
it_original_data = it_original_data
CHANGING
ct_calc = lt_calc.

ENDIF.
* IF line_exists( it_requested_calc_elements[ table_line = cs_cal_element_variant-variantenabled ] ).
* CALL METHOD set_varaintenabled
* EXPORTING
* iv_uname_type = ‘VARIANTENABLED’
* it_original_data = it_original_data
* CHANGING
* ct_calc = lt_calc_variant.
* ENDIF.
* IF line_exists( it_requested_calc_elements[ table_line = cs_cal_element_variant-variantenabled ] ).
* MOVE-CORRESPONDING lt_calc_variant TO ct_calculated_data.
* ELSE.
MOVE-CORRESPONDING lt_calc TO ct_calculated_data.
* ENDIF.

ENDMETHOD.

METHOD if_sadl_exit_calc_element_read~get_calculation_info.

ENDMETHOD.

METHOD set_full_name.

DATA: ls_user TYPE i_user.

FIELD-SYMBOLS: <fs_calc> TYPE any,
<fs_createdby> TYPE simple,
<fs_createdbyusername> TYPE simple,
<fs_changedby> TYPE simple,
<fs_changedbyusername> TYPE simple.
IF ct_calc IS INITIAL.
MOVE-CORRESPONDING it_original_data TO ct_calc.
ENDIF.

IF iv_uname_type = ‘CREATEDBY’.
LOOP AT ct_calc ASSIGNING <fs_calc>.
ASSIGN (‘<fs_calc>-createdbyusername’) TO <fs_createdbyusername>.
CHECK sy-subrc = 0.
ASSIGN (‘<fs_calc>-CreatedByUser’) TO <fs_createdby>.
CHECK sy-subrc = 0.

IF <fs_createdby> IS NOT INITIAL.
SELECT SINGLE * FROM i_user INTO @ls_user WHERE userid = @<fs_createdby>.
IF sy-subrc = 0.
<fs_createdbyusername> = ls_user-userdescription.
ENDIF.
ENDIF.
ENDLOOP.
ELSEIF iv_uname_type = ‘CHANGEDBY’.
LOOP AT ct_calc ASSIGNING <fs_calc>.
ASSIGN (‘<fs_calc>-lastchangedbyusername’) TO <fs_changedbyusername>.
CHECK sy-subrc = 0.
ASSIGN (‘<fs_calc>-LastChangedByUser’) TO <fs_changedby>.
CHECK sy-subrc = 0.

IF <fs_changedby> IS NOT INITIAL.
SELECT SINGLE * FROM i_user INTO @ls_user WHERE userid = @<fs_changedby>.
IF sy-subrc = 0.
<fs_changedbyusername> = ls_user-userdescription.
ENDIF.
ENDIF.

ENDLOOP.
ENDIF.

ENDMETHOD.

METHOD set_varaintenabled.
DATA: lt_product TYPE itproductwd,
ls_product TYPE isproductwd.

FIELD-SYMBOLS:
<fs_variantenabled> TYPE simple,
<fs_productforedit> TYPE simple.
IF ct_calc IS INITIAL.
MOVE-CORRESPONDING it_original_data TO ct_calc.
ENDIF.

IF iv_uname_type = ‘VARIANTENABLED’.
LOOP AT ct_calc ASSIGNING FIELD-SYMBOL(<fs_calc>).
ASSIGN (‘<fs_calc>-variantenabled’) TO <fs_variantenabled>.
CHECK sy-subrc = 0.
ASSIGN (‘<fs_calc>-productforedit’) TO <fs_productforedit>.
CHECK sy-subrc = 0.
IF <fs_variantenabled> IS INITIAL.
SELECT SINGLE * FROM i_productwd INTO @DATA(ls_product_p) WHERE productforedit = @<fs_productforedit>.
IF sy-subrc = 0.
MOVE-CORRESPONDING ls_product_p TO ls_product.
INSERT ls_product INTO TABLE lt_product.
else.
SELECT SINGLE * FROM prod_root INTO @DATA(ls_product_d) WHERE productforedit = @<fs_productforedit>.
MOVE-CORRESPONDING ls_product_d TO ls_product.
INSERT ls_product INTO TABLE lt_product.
endif.

IF lt_product is not initial.
CALL METHOD cl_variant_checks_util=>is_variant_ui_enabled
EXPORTING
it_product = lt_product
IMPORTING
et_message = DATA(lt_message)
ev_success = DATA(lv_success).
IF lv_success = abap_true.
<fs_variantenabled> = ’02’.
else.
<fs_variantenabled> = ’01’.
ENDIF.

ENDIF.
ENDIF.

ENDLOOP.

ENDIF.
ENDMETHOD.
ENDCLASS.

 

 

Personal opinions:

  • “CDS View published as OData Service” or “CDS View with UI annotation” does not need to be created from Interface View technically, but I think it is better to do so as much as possible because of the standardization of the modeling. Anyway, application specific view needs to be created, and Interface View cannot be consumed by application directly in general.
    • This means, master view associations and foreign key associations should be set in Interface View as much as possible. For Fiori Elements apps, Master View would be needed for value help in its Consumption View, technically, the exposed master view associated in the source Interface View (e.g. _Plant) could be used in the Consumption View created on top of it. But if some specific settings are needed in the value help, e.g. fuzzy search, projection (limit the attribute), another master view for value help would be needed.
  • I think Interface View should be created to be supposed to be used for many purposes and should avoid having application specific settings as much as possible like BW Infoprovider and InfoObject are supposed to be reused for many reports.
    • So, In my opinion, Calculated measure (and Restricted measure) should be created in Consumption View, not in Interface View, as much as possible. It is because by using annotation “@AnalyticsDetails.query.formula”, the calculated measure created in the same analytic query can be used in the formula. In the standard predefined VDM used in KPI tile or Fiori Elements apps, it is not the case. But I think it is beneficial as we can avoid creating several source CDS Views to add calculated measures. But calculated measures/restricted measures supposed to be reused by many apps, it should be created in Interface View. In addition, if master views for value help have to be used in the consumption view for Fiori Elements, it is not the case and it cannot be set as analytic query.
    • In addition, I believe parameters should be set in Consumption View, not in Interface View, as much as possible as in general parameters are application specific. But if the parameter values are not pushed down to the source tables/views, they need to be created in the lower views to use it in the WHERE condition explicitly. But as SELECT statement is optimized internally in HANA, WHERE conditions for normal columns (dynamically generated by the navigations in an application) should be pushed down to lower tables/views in general, so it is not necessary to use parameter instead of normal column filtering.
    • WHERE condition should not be included in Interface View as much as possible as Interface View should be supposed to be used also for the queries which need to all data in the source.

But they are only my current personal opinions, and I think there are some other ones who have different opinions but are also good. I would like you to share your opinions.

 

Training

It is recommended to participate in the following training courses.

S4D430 Building Views in Core Data Services ABAP (CDS ABAP)

S4H41E S/4HANA embedded analytics and Modeling Basics with Core Data Services (CDS Views)

or

S4H410 S/4HANA embedded analytics and Modeling Basics with Core Data Services (CDS Views)

 

Hope it help understanding overall of the CDS View!

12 Comments
You must be Logged on to comment or reply to a post.