ABAP Programming Model For Fiori EN
ABAP Programming Model For Fiori EN
2020-10-06
3 Get Started. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.1 Developing a Simple List Reporting App . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
Define a Data Model Based on CDS Views. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .13
Generating OData Service With Auto-Exposure. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
Consume Business Data Using SAP Fiori Elements. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
4 Concepts. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
4.1 Draft Concept. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .35
4.2 Draft Consistency. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .40
4.3 Locking and Resume . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
4.4 Messages. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
4.5 Validations for CDS-Based Business Objects. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
4.6 Actions for CDS-Based BOPF Business Objects. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .60
4.7 Determinations for CDS-Based Business Objects. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
5 Develop. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
5.1 Developing List Reporting Apps with Search and Analytical Capabilities. . . . . . . . . . . . . . . . . . . . . . 67
Data Model Without Metadata - Starting Point. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
Adding Metadata to Data Model. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
Running Resulting App . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .75
5.2 Developing New Transactional Apps . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
Defining the Business Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
Implementing a Service-Specific Consumption View . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
Running the Resulting SAP Fiori App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
Extending Apps with Quick Actions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
5.3 Developing New Transactional Apps with Draft Capabilities . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .105
Defining the Draft Business Object for Sales Order. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
Providing Additional Business Logic with a BOPF Determination. . . . . . . . . . . . . . . . . . . . . . . . 121
Defining the Consumption Layer. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
Adding UI Semantics for Consumption in Fiori UI. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
Running the Resulting Fiori App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
Extending the Implementation for Adding New Sales Order Items. . . . . . . . . . . . . . . . . . . . . . . 132
Extending the Implementation with Value Validation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
7 Extend. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .172
7.1 Extending Apps with Custom Code. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
Creating an Appropriate CDS View Extension. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178
Adding Custom Fields to Extension View . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
Adding Fields from Association . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
Running the Resulting Fiori App. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 184
7.2 Metadata Extensions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
9 Reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361
9.1 CDS Annotations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 361
AccessControl Annotations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 362
Analytics Annotations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367
AnalyticsDetails Annotations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 379
Consumption Annotations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390
Aggregation Annotations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 414
EnterpriseSearch Annotations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 420
Hierarchy Annotations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 422
ObjectModel Annotations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 428
OData Annotations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .441
Search Annotations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 442
Semantics Annotations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 445
UI Annotations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 465
VDM Annotations. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .587
9.2 Understanding the BOPF Authorization API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 592
Method CHECK_STATIC_AUTHORITY. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 594
Method CHECK_INSTANCE_AUTHORITY. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .596
Context Information for Implementing Authorization Checks. . . . . . . . . . . . . . . . . . . . . . . . . . 599
11 Glossary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .606
The ABAP Programming Model for SAP Fiori defines the architecture for efficient end-to-end development of
intrinsically SAP HANA-optimized Fiori apps in SAP S/4HANA. It supports the development of all types of Fiori
applications like transactional, search, analytics and planning apps and is based on customer-proven
technologies and frameworks such as Core Data Services (CDS) for defining semantically rich data models,
OData protocol, ABAP-based application services for custom logic and SAPUI5-based user interfaces – as
shown in the figure below.
Main building blocks of the ABAP programming model for SAP Fiori
Target Audience
ABAP developers who want to provide OData services within the scope of ABAP programming model for SAP
Fiori.
This documentation refers to the range of functions that have been shipped as part of delivery for AS ABAP
7.54, SP00.
Classification of ABAP Programming Model for SAP Fiori within the Evolution of Programming Model
●
●
The ABAP Programming Model for SAP Fiori is based on modern and proven technologies such as CDS, BOPF
and SAP Gateway. A lightweight CDS-based flavor of the BOPF framework is used in this context for the
transactional processing. This programming model is generally available to customers and partners within
ABAP Platform starting with release 7.50 SP00.
For more information about the evolution of the ABAP programming model, read this blog on the
community portal.
Contents
2.1 Prerequisites
Development Environment
● We recommend to use the latest version of ABAP Development Tools for SAP NetWeaver (in short: ADT).
Tip
You can download the latest available ADT plugin from the update site https://
tools.hana.ondemand.com/#abap
SAP Gateway
● SAP Gateway is properly configured in your ABAP system for activating and testing the resulting OData
service. More on this on the SAP help portal: SAP Gateway Foundation.
Authorizations
To reproduce the steps described in this guide, the user on SAP Netweaver Application Server with the
following roles assigned is required:
● SAP_BC_DWB_ABAPDEVELOPER
● SAP_BC_DWB_WBDISPLAY
Knowledge
Basic knowledge of
Contents
Introduction
In this Getting Started section, you have the opportunity - starting from an already existing data model - to
develop a simple list - reporting scenario based on the standardized ABAP programming model for SAP Fiori.
You will be guided step-by-step through the new development infrastructure, which includes technologies such
as Core Data Services (CDS), SADL, and SAP Gateway. In this scenario, the assumption is that the business
logic is already provided with the FPM application model and that it allows users to create and manage sales
orders. In the first step, you will use the well-known ABAP Development Tools to implement a CDS
consumption view as a new data model layer, using a data source that is already provided with the EPM
application. From within your development environment, you can continue with the next step towards
consumption of the corresponding OData service. Here, you will use the CDS tools as part of the ABAP
development environment to generate all artifacts that are required for service activation in the SAP Gateway
hub. As soon as the OData service is activated in the SAP Gateway, it is ready for consumption through an
OData client, such as an SAP Fiori app. Therefore, in our final step, we are going to build a Fiori UI using Smart
Templates as Fiori building blocks. Finally, you can test the resulting list-reporting app within the SAP Fiori
Launchpad environment.
Video Available
Objectives
By the end of this Getting Started section, you will be able to...
● Create a DDL source in ABAP Development Tools for defining an ABAP CDS view
● Implement an ABAP CDS view for a simple data model based on existing data definition from EPM scenario
● Understand some basic CDS view annotations
● Perform a so-called auto-exposure process, which automatically exposes the CDS view as an OData
service to the SAP Gateway hub
To define a data model based on the ABAP CDS view concept, you first need to create a DDL source as the
relevant ABAP repository object using a wizard in ABAP Development Tools.
In the second step, you will implement an elementary CDS view from scratch by defining a simple query for
sales order items based on a single data source from EPM demo application.
In the last task of this section, you have the option to try out the test environment for verifying the output
(result set) of the CDS view you have just implemented.
Task 3: Verify the Result Set in the Data Preview Tool [page 18]
Prerequisites
You need the standard developer authorization profile to create ABAP development objects.
Context
A Data Definition represents an ABAP development object used to define an ABAP CDS entity (for example, a
CDS view). With the Data Definition you have the appropriate development object for the CDS view, which you
can use to directly access the standard ABAP Workbench functionality, such as syntax check, activation, or
connecting to the Transport Organizer.
Procedure
Note
In the selected package, the ABAP back-end system creates an inactive version of a Data Definition and stores
it in the ABAP Repository. As a result of this creation procedure, the Data Definition editor will be opened. The
generated source code already provides you with the necessary view annotations and adds placeholders for
names of the Dictionary SQL view, the actual CDS view, and for the data source for query definition.
Context
In this step, you will implement a projection view as a new data model using a data source that is already
predefined in the EPM demo scenario.
Procedure
1. If you have not yet already done so, open the newly created DDL source in the text-based DDL editor.
2. Specify the names of the...
a. SQL view to be generated in the ABAP Dictionary: ZDEMO_SOI
b. Actual CDS view: ZDEMO_CDS_SalesOrderItem
3. In the SELECT statement, enter the predefined CDS view SEPM_I_SalesOrderItem_E as data source
and define Item as alias name for the data source.
... select from SEPM_I_SalesOrderItem_E as Item {
4. Add the Item fields to the SELECT list (as they are required for new projection view) and assign the alias
names to each item field as follows:
Tip
Whenever you insert table or view fields in the SELECT list, you can avail of the Content Assist
functionality in the DDL editor.
Item.SalesOrder as SalesOrderID,
Item.SalesOrderItem as ItemPosition,
Item._SalesOrder._Customer.CompanyName as CompanyName,
Item.Product as Product,
Item.TransactionCurrency as CurrencyCode,
Item.GrossAmountInTransacCurrency as GrossAmount,
Item.NetAmountInTransactionCurrency as NetAmount,
Item.TaxAmountInTransactionCurrency as TaxAmount,
Item.ProductAvailabilityStatus as ProductAvailabilityStatus
5. To document the key semantics of the new data model, define the SalesOrderItem and the
ItemPosition fields as KEY elements in the current CDS view:
...
key Item.SalesOrder as SalesOrderID,
key Item.SalesOrderItem as ItemPosition,
...
Tip
To insert an annotation, type the first letter(s) of the annotation and then press CTRL + Space .
...
@Semantics.currencyCode: true
Item.TransactionCurrency as CurrencyCode,
@Semantics.amount.currencyCode: 'CurrencyCode'
Results
The resulting source code for the CDS view is the following:
@AbapCatalog.sqlViewName: 'ZDEMO_SOI'
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'List Reporting for Sales Order Item'
The source code above is used to define quite a simple CDS view named ZDEMO_CDS_SalesOrderItem. This
view is implemented by means of a query for performing a SELECT statement, where the predefined CDS view
SEPM_I_SalesOrderItem_E is used as the data source. The select list includes a set of fields that are
relevant for the new sales order item projection view. The KEY elements in the selection list are used to define
the key field semantic of the CDS view. The element CurrencyCode is defined as currency key using the
annotation @Semantics.currencyCode: true. The annotation @Semantics.amount.currencyCode:
'CurrencyCode' defines each amount element as a currency field.
When the DDL source is activated, the following objects are created in ABAP Dictionary:
Prerequisites
Context
Now you have the option to launch the test environment (Data Preview tool), which will enable you to verify the
result set of a CDS view.
Procedure
1. In the DDL editor, position the cursor somewhere in the CDS source code.
2. Open the context menu and choose Open With Data Preview .
Results
Since the CDS view does not require any parameters, the Data Preview displays the result set of the data
selection query directly.
OData Exposure
With the concept of auto-exposure, a new and simple way of creating OData services has been introduced.
Here, the OData model definition as well as the OData service runtime is provided generically, based on SADL
(Service Adaptation Description Language).
The requirement here is that the annotation @OData.publish:true is specified at the CDS data model (CDS
consumption view) level as follows:
@AbapCatalog.sqlViewName: 'SQL_VIEW_SAMPLE'
...
@OData.publish: true
define view CDS_VIEW_NAME as select from
...
}
Remember
We recommend using the auto-exposure option in the case of elementary data model compositions: for
example, if you defined the entire CDS data model based on a root CDS view so that several other CDS
views are children of this root CDS view. In addition, the CDS views of this composition might have
associations to other entities. In cases like this, all the CDS views together form a quite simple data model
composition that you want to expose as an OData service, together with first the level of associations.
● Your data model composition is more complex and you need to include deeper association levels in
your OData service.
● You want to generate a hybrid scenario where implementations are based on CDS views and on custom
logic.
The following figure depicts the main components of the auto-exposure process and refers to the most
important activities that are involved:
Starting in ABAP Development Tools, you open the relevant CDS data definition object where the CDS view in
question is implemented. After you have added the OData annotation to the CDS view, you can trigger the
activation of the entire CDS data definition (that serves as transportable development object). ABAP
Development Tools delegates the activation request to SADL. SADL framework generates several SAP Gateway
artifacts that are stored in the back end of the application server AS ABAP and are required for OData service
activation in the SAP Gateway hub system.
Included components and involved activities when exposing CDS-based data model to OData
Developer-Relevant Tasks
As a result of this task, several service artifacts are generated in the back end of the application server.
Task 2: Activate OData Service in the SAP Gateway Hub [page 22]
As a result of this task, the OData service is added to service catalog of the SAP Gateway hub and is ready for
consumption.
Here, we want to expose the newly developed data model to OData as a canonical OData service using the so-
called auto-exposure approach. In this step, you will use the CDS tools as part of the ABAP development
environment to generate all artifacts that are required for service activation in the SAP Gateway hub.
Prerequisites
● The CDS view is defined and the source code of the corresponding data definition source is syntactically
correct.
● At least one KEY element is defined in the SELECT list of the CDS view. Otherwise, the OData service
generation will fail due to missing KEY elements in the CDS view.
● The name of the CDS view in question does not exceed the maximum length of 26 characters.
Tip
If this is not the case, use the refactoring function for renaming.
Procedure
1. In the ABAP Development Tools, open the editor with the relevant data definition where your CDS view is
defined.
2. In editor, navigate to the source code line before the DEFINE VIEW statement.
3. Insert the following OData annotation to the CDS view:
@OData.publish: true
4. Save the new editor content and activate the data definition of the CDS view.
More on this:
ABAP Development Tools delegates the activation request to the SADL (Service Adaptation Description
Language) framework. SADL, in turn, generates several SAP Gateway artifacts that are stored in the back end
of the application server AS ABAP and are required for OData service activation in the SAP Gateway hub later
on:
● The actual service object with the technical name <CDS_VIEW>_CDS. You can find it as SAP Gateway
Business Suite Enablement - Service object (object type: R3TR IWSV)
● An SAP Gateway model (object type: R3TR IWMO) with the name <CDS_VIEW>_CDS
● An ABAP class <NAME_SPACE>CL_<CDS_VIEW> that is used to provide model metadata to the SAP
Gateway service.
All generated service artifacts are automatically added to the same ABAP package (and also to the same
transport request) as the underlying CDS view.
Note
The warning decorator within the editor ruler indicates a successful generation process. If you move the
cursor over the decorator, an info screen informs you that the service artifacts have been generated for the
CDS view. However, the service must be activated in the SAP Gateway hub for exposure. This will be done
manually in a separate step using the transaction /IWFND/MAINT_SERVICE.
More on this: Activate OData Service in the SAP Gateway Hub [page 22]
After you have generated the SAP gateway artifacts in your development environment, you can continue with
the next step towards consumption of the OData service. For this you need to activate the OData service in the
SAP Gateway hub. In other words: The OData service has to be enabled in SAP Gateway which establishes a
mapping between the technical OData service name and the corresponding back end service.
Prerequisites
● The service artifacts are successfully created in the back end of the application server AS ABAP.
● The SAP Gateway hub (target system for the OData service) is set up and configured for managing OData
services. More on this: Quick Configuration
● You have the authorization for using activation functionality in the transaction /IWFND/MAINT_SERVICE.
1. Open the SAP GUI for the relevant ABAP project by starting the SAP GUI Launcher ABAP Development
Tools (icon in the toolbar). Within the embedded SAP GUI, you are able to access the complete
functionality of the classic ABAP Workbench.
Note
Alternatively, you log in to the corresponding development system using the SAP GUI mode.
The entry screen of the transaction displays in the target system all activated Gateway services in the
Service Catalog and allows you to add new services.
3. Click the Add Service button in the toolbar.
4. Enter the System Alias of your front-end server.
5. Enter the Technical Service Name (in our case: <CDS_VIEW>_CDS).
Editing details for the service to be activated in the Gateway hub (in our case: LOCAL system)
6. Click the Get Services button in the toolbar to request the services available.
The Add Service dialog that appears, suggests already the name <CDS_VIEW>_CDS for the Technical
Service, and for the Technical Model.
Note
We recommend that you do not change the suggested technical names <CDS_VIEW>_CDS for the
service and the model.
The dialog that now appears informs you that the model metadata for the Gateway service is going to be
created.
8. Specify the package for service activation.
Assign a productive package (none $TMP package) only if you want to transport the service activation
within in your system landscape.
9. Leave the other details on the dialog screen unchanged, and choose (Continue).
Dialog
Dialog that informs you about a successful service creation (example for $TMP package)
Results
As a result of the successful procedure, the OData service has been activated in the Gateway hub. During this
activation, further new objects have been created:
● SAP Gateway: Service Group Metadata object (object type: R3TR IWSG) with the name
Z<CDS_VIEW>_CDS_<VERSION> that object type IWSG that includes the service group metadata of the
Gateway represents the actual OData service.
● An SAP Gateway: Model Metadata object (object type: R3TR IWOM) with the name
Z<CDS_VIEW>_CDS_<VERSION>_BE that represents the structure of the actual OData service.
● In addition, an ICF node (object type: SICF) for the OData service has been generated.
Prerequisites
To run the newly developed and activated OData service, we assume that...
● Authorization defaults are assigned to the new service using transaction SU24 (SAP customers) or SU22
(SAP internal). More on this: Assigning Authorization Defaults to OData Services [page 167]
● Your authorization role is extended in transaction PFCG for using the new service. More on this: Assigning
Authorizations to Roles [page 169]
Remember
When developing new OData services within the SAP internal development landscape, usually it is not
necessary for you, as ABAP developer at SAP, to take care for these authorization requirements.
To test the new service from the Service Catalog, select the newly created service and choose SAP Gateway
Client.
If you want to know more about the SAP Gateway Client, see SAP Gateway Client .
If the SAP Gateway and the back end are in the same ABAP system and you open the editor with the data
definition of the relevant CDS view again, you will detect that a new decorator indicates a successfully
activated OData service. If you move the cursor over the decorator, an info screen provides you with a link to
the OData service.
Quick info after successful service activation in the case of an embedded SAP Gateway
In this final procedure, we are going to build a quite simple list-reporting Fiori UI without any code using the
OData service (that you created in the last procedure) as the data source. In the course of the UI development,
Developer-Relevant Tasks
Task 1: Create a Project for a Fiori App in the Web IDE [page 28]
Task 2: Run the New App in the Fiori Launchpad [page 31]
Related Information
Prerequisites
● You are registered in the cloud for using SAP Web IDE in the cloud.
More on this: SAP web IDE - Getting Started
● You have the authorization for using the SAP Web IDE (role WebIDEPermission).
More on this: SAP web IDE - Assigning Roles to Permissions
● The system connection to the relevant SAP Gateway system is configured using the SAP HANA Cloud
Connector and available from within the SAP Web IDE.
Procedure
Annotation Selection: In our special case, the OData service does not provide any available UI-related metadata
7. Assign the name of the original data model (CDS consumption view) to Data Binding template parameter.
Then choose Next.
Results
The project wizard creates the SAP Fiori app based on Fiori Elements. The SAP Web IDE automatically opens
the new project in the workspace under a folder with the project name that you specified and displays the
project tree:
Based on the OData service metadata, you have created a project for your SAP Fiori app in SAP Web IDE and
want to run the new app in the Fiori Launchpad.
Prerequisites
● Authorization defaults are assigned to the new service using transaction SU24 (SAP customers) or SU22
(SAP internal). More on this: Assigning Authorization Defaults to OData Services [page 167]
● Your authorization role is exteded in transaction PFCG for using the new service. More on this: Assigning
Authorizations to Roles [page 169]
Context
An app based on SAP Fiori elements uses predefined template views and controllers that are provided centrally,
so that no application-specific view instances are required. The SAP UI5 runtime interprets metadata and
annotations of the underlying OData service and uses the corresponding views for the SAP Fiori app at start up.
To run the resulting list-reporting app for sales order items, we will be using a local sandbox for the SAP Fiori
launchpad as a simplified environment that you can use for local testing. This ensures that the app can be
embedded properly into the SAP Fiori launchpad.
To run and test your app without defining a new run configuration, proceed as follows:
1. In the SAP Web IDE, select the project you want to run.
2. In the main toolbar, click the Run button.
Running project
Selecting columns
6. Choose the Go button.
Results
Contents
Motivation
SAP’s traditional applications are developed using stateful technologies, such as Floorplan Manager (FPM) for
WebDynpro ABAP or the classic Dynpro technique. These stateful transactional applications rely on a server
session along with application buffers that can fulfill client requests (user interactions with multiple backend
round trips) until the user has saved the data changes and finished his/her work – as illustrated in figure (a)
below. In stateful applications, data entry and data updates work on a temporary in-memory version of a
business entity which is only persisted once it is sufficiently complete and consistent. The life time of this
temporary version is tied to the UI session.
As an application developer, you might need to enable the end user to store changed data at any time in the
backend and continue at a later point in time or to recover this data, even if the application client has crashed.
This kind of scenario needs to support a stateless communication and requires a replacement for the
temporary in-memory version of the business entity that is created or edited. This temporary version is kept on
the database and is known as a "draft". As illustrated in figure (b) below, drafts are isolated in their own
persistency and do not influence existing business logic until activated.
In addition to replacing UI sessions, the draft concept introduces many new opportunities:
● Draft data can be stored any time without having to meet any criteria regarding consistency or
completeness, thus minimizing the risk of data loss due to network, server, or client failures.
Restriction
At the present point in time however, SAP’s implementation of the draft framework supports exclusive
draft capabilities only. Therefore, the draft is locked for a specific (exclusive) user only and no collaborative
activities are possible on one and the same draft version of data.
As stated above, traditional business applications only store the most recent version of a business entity data
in the database. This results in the following situations however:
● A new business entity is created in transient memory only; no persistent version exists in the database.
● The most recent persistent version of the business entity exists in the database.
● If an existing business entity data is being edited by a user, two versions of this business entity exist in
parallel: the transient version with changes made since editing started, and a persistent version with the
content before editing started.
To base an application on stateless communication without feature loss, the following three states of business
entities are required:
The figure below illustrates the states of the business entities and their transitions following various actions
triggered by the user.
The life cycle of a business entity starts with the creation of a new draft. This initial draft can be empty or can
contain default values derived from system preferences and related business entities, calculated values, or field
control information. For a new sales order item that is being created for example, the item position can be
calculated, and a product can be selected from the product catalog.
New user inputs or data updates for an existing business entity start with the creation of an edit draft version
as a copy of active data. The new or changed data is stored in the draft persistence regardless of its validity or
completeness. User inputs can also be immediately validated however. The consistency of the draft can be
checked using the VALIDATION action. This will return messages, each with a reference to the critical part of
the draft. The VALIDATION action is free from side-effects, meaning that it simply returns messages as a result
of consistency checks. The draft can be enriched by calling a PREPARATION action. PREPARATION actions can
have side-effects and modify the draft. They can also return messages as a result of consistency checks or the
business logic triggered by them.
The draft version is converted into active data by calling the ACTIVATION action. This will implicitly trigger the
VALIDATION action on the draft. The draft is also deleted after successfully copying its data into active data of
the business entity.
BOPF provides additional functionality for draft support at the business object level. In addition to the standard
BOs, it is possible to create a specific shape of BOs that is suited for implementing draft qualities. Draft
business objects provide code exits for implementing the draft contract and extending the BO functionality
based on well-defined BOPF APIs.
Applications with draft support can deal with two BOPF business object instances:
● The active instance represents the state of the business object (sales order) instance that is stored in the
active persistence (active table).
● The draft instance represents the temporary version (transient state) of a business object instance until it
is permanently stored in the persistence layer as an active instance. The draft data is stored in the draft
persistence (draft tables) until its transition to active data.
Draft support for BOPF business objects – transition from draft to active BO instance
In order to consume draft data in a generic manner, the BOPF framework by default creates standard draft
actions (as mentioned above), such as EDIT, ACTIVATION, PREPARATION, and VALIDATION, for each draft
business object.
Draft-Enabled Associations
As stated above, every BO entity with draft support can have more than one version of data: The active
instance and the draft instance. Consequently, when following an association from one draft-enabled entity to
another one, the data returned by the association can be either the active or the draft version. Whether the
association navigates to the active or the draft instance of the target entity depends on the association being
draft-enabled or not.
A draft-enabled association retrieves active data if you follow it from an active source instance. It retrieves draft
data if the association is followed from a draft source instance. On the other hand, an association that is not
draft-enabled always retrieves active data even if the source instance is draft.
Some associations are draft-enabled by default. This is the case, when the associated entities belong to the
same business object instance (identified by the same root key). All other associations need to be
implemented to become draft-enabled. The implementation for draft-enablement is done by annotations on
the respective association.
Draft versions of business objects data are made visible in SAP Fiori UI to the end user in order to distinguish
them from the application’s active data. The figure below displays the UI for a sales order processing app,
where the end user can list all sales orders available in the system and perform all CRUD operations on sales
order instances. The resulting Fiori app also provides draft-enabling capabilities. For each sales order instance
for which draft data also exists, the indication Draft is added to the sales order ID field. An additional filter for
Editing Status is also provided to the end user to indicate specific draft instances.
User input is therefore implicitly stored as a draft version. In the “minimize data loss” use case, the user has to
decide at the end of an application whether s/he wants to activate or discard the draft data version. If the
application ends in an uncontrolled way, the draft will be available when the user re-starts the application.
Related Information
Here we explain how the ABAP application infrastructure is used in transactional applications to ensure the
data consistency for draft instances of business objects.
● How the ABAP application infrastructure prevents a draft instance with inconsistent data from beeing
activated
Prerequisites
Your application scenario uses drafts. This includes draft BOPF business objects that are generated in
accordance with the CDS-based data model.
Addressed Requirements
In transactional application scenarios that implement drafts, the user can, in principle, enter arbitrary data as a
draft data. This means that inconsistent data can also be stored in a draft version.
However, the application infrastructure should automatically prevent draft instances of business objects with
inconsistent data from beeing activated. Consistency validation should be able to ensure that only consistent
draft data can be permanently stored in the persistence layer as an active instance. In addition, the result of
rejected activations could return a list of messages, each with a reference to the problematic part of the draft,
to the consumer.
Remember
The consistency of drafts is implicitly ensured by the ABAP application infrastructure. In some rare cases,
however, you as a developer should be able to check the consistency status for each individual draft
instance in your application scenario.
To identify a draft instance that contains inconsistent data, a suitable marking is required. For this reason, each
ROOT node of a draft business object has a technical field that is named DRAFTENTITYCONSISTENCYSTATUS.
This field represents the consistency status of the entire draft instance. Activation of a draft instance is only
possible if the status is consistent.
The field DRAFTENTITYCONSISTENCYSTATUS can have three different values that are defined in /BOBF/
IF_FRW_C:
The value of the consistency status field is automatically defined by the ABAP application infrastructure
(BOPF) using built-in status handling, namely as follows:
As a developer, you have the option of checking the consistency status for each individual draft instance.
The diagram below describes the process of draft activation. As you can see in the life-cycle diagram of the
draft topic [page 37], the activation can be applied to the New Draft and the Edit Draft states.
If the user interface sends an OData POST request for draft activation to the service layer, the request is
forwarded to the BOPF framework that is part of the ABAP application infrastructure. This infrastructure
evaluates the consistency status of the draft instance. The consistency validation implicitly executes the
PREPARATION action and sets the value of the draft consistency field. (The implicit execution of
PREPARATION, however, requires that the POST request is part of a single change set and no other changes
are included in this change set - besides those that result from the ACTIVATION action.)
If this status is pending or inconsistent, the activation action is rejected. In this case, because of consistency
checks or other business logic triggered by it, only a list of messages is returned, each with a reference to the
problematic part of the draft.
Otherwise, the draft can be converted into an active instance: either a new active instance is created when
activating a New Draft or the existing active instance is modified when activation is applied for an Edit Draft.
Also, the draft is deleted after its data is copied to an active instance.
Related Information
Traditional transactional ABAP applications are developed on a stateful programming model. These
applications rely on the server session, along with application buffers that can fulfill client requests until the
user has successfully saved or discarded the data changes and finished his/her work.
The stateful programming model supports the processing of in-memory copying of business entities (such as
business objects instances) in an incremental way, involving user interactions with multiple round trips
Newer business applications follow a stateless programming paradigm, which offers better scalability by
avoiding a difficult behavior of application states on the application server. The application scenario might
require the data from business entities to be held across multiple interaction steps that can triggered by
multiple users.
Since the communication in this case is based on a RESTful protocol, there is no ABAP session continuously
available. In a stateless approach without a continuous session, a persistent counterpart needs to replace the
in-memory copy of the business entity data to keep the state across requests. Moreover, locks are decoupled
from the session and bound to the lifecycle of the draft – as depicted in the figure below.
● Each atomic writing operation (create, update, update, and so on) executed during the interaction phase
will result in a separate commit, preceded by corresponding validations. Editing a single entity (business
object instance) therefore typically involves multiple validations.
● Missing isolation - Since multiple users can collaborate on the same business entity, this can result in
concurrent execution of operations that affect the state of the entity. In other words, a single user can
create intermediate states on entities that do not appear for other users.
● Each writing operation must result in a consistent state, since validation might reject writing. It is therefore
not possible to save an intermediate state during the creation of a new business entity.
For some specific applications, it would suffice to shift the application logic to the UI layer. With this approach
however, the development infrastructure would have to ensure that all required data from the back end is
replicated to the front end after the incoming request. In this case, the state of the data would be kept at the
front end. Only the end states would be passed on to the back end.
The effort involved for data transfer in typical business applications can become quite high however.
Calculations that take place at the back end could sometimes transfer large result sets to the UI. In addition,
The data from business entities that is to be held over multiple interaction steps is therefore kept in a draft
version. This draft is a temporary collection of changes made to the data. At the user's activation request, the
changes can be applied as active data, and the draft deleted. With this draft concept, all data changes are
persisted in draft tables, which are shadow tables of the original data, to ensure that the draft data is not
accidently processed by any kind of reporting for example. More on this: Draft Concept [page 35]
In addition, regular enqueue locks are extended to allow decoupling locks from ABAP session lifecycle: durable
locks. In this context, the term durable expresses the capability to preserve an enqueue lock even after ending
the session or when committing data in an intermediate step to persist the state of a draft entity. Durable locks
can therefore be kept across multiple OData requests of a client, each processed in its own session.
This approach has many benefits: Since the state is continuously transferred to the back end, the business
logic can be invoked to provide the end user with feedback related to the data entries. Furthermore, additional
UX qualities such as continuous work, device switch and data loss preventions can be achieved, since the
persisted state in the draft tables is decoupled from the ABAP session, from the end user, and even from the
device.
As shown in the figure below, the draft acts as a locking instance in its own right:
New user inputs or data updates (subsumed in the EDIT action) for an existing business entity start with the
creation of a draft entity as a copy of active entity. The EDIT action creates an exclusive lock on the active entity
so that no further changes can be made to the active data. Since the draft lifecycle does not have a short
timeout behavior (otherwise we would not achieve the draft qualities), the lock needs to be removed to ensure
a proper workflow. To enable collaborative work on the business entity, the expiration period of this exclusive
lock is therefore limited. It starts with the first modification of the draft entity and ends with a lock timeout
(which is configurable).
Note
In comparison to the ABAP session with a single timeout, the draft makes it possible to separate the data
timeout from the lock timeout.
Once the timeout of the exclusive lock has occurred (if the user has been inactive for a substantial period of
time for example), the durable lock is removed, and the draft is operated in an optimistic lock mode.
The corresponding ETag value of the active entity (time stamp of the last data modification, for example) is
included in additional administrative data of the draft entity. It is used to determine whether two
representations of a business entity, such as an active instance and the corresponding draft BO instance, are
the same. If the representation of the entity ever changes, a new and different ETag value is assigned. An ETag
check is used to determine whether an optimistically locked draft still matches the current version of the
related active instance.
Once the user continues working on draft data, the draft state must be resumed. As depicted in the figure
below, resume re-acquires the exclusive locks.
There is not guarantee however that resume will be successful, since changes might have been applied in the
meanwhile (as could always be the case in an optimistic lock phase). Another user (U2) might have changed
the related entity for example. In this case, the first user U1 loses his/her draft D1, and a newer version D2 will
be created. If user U1 tries to access D1, s/he gets the response: resource not found. (If on the other hand user
U2 does not change the related entity, the original draft D1 of the entity is retained and can be further
processed after resumption.) Optimistic mode avoids a lock conflict in any case.
Before resuming a draft, the ETag of the active instance is checked. If the ETag has been changed, this
results from changes to the active instance during the optimistic lock phase. The old draft then cannot be
resumed, and a new draft from the active instance must be created.
A durable lock is requested using an enqueue context. This context serves as the unique identifier of a lock
phase during which cross-session locks are assigned to this context. A draft is associated with its enqueue
context through an ID. If, a legacy application uses function modules to acquire its own locks on certain
resources for example, the locks from the legacy code must be made durable for as long as the draft exists. The
enqueue context therefore integrates locks from the legacy code into the lock phase of the durable locks.
Note that the enqueue context, and all locks assigned to it, will be removed if the corresponding draft is not
edited for a certain period of time (timeout). Once the user continues working on the draft, the draft state must
be resumed.
For editing a specific draft, this means that the resume() method of the framework interface /BOBF/
IF_FRW_DRAFT is called whenever the lock on the active entity is reacquired after being lost because of a
timeout of the assigned enqueue context (or for other technical reasons).
Remember
Resumptions of locks on active instances is performed by the framework. To this, it executes the LOCK
action and runs the ETag check. Certain application scenarios can require additional locks however. Only
then is implementation of the resume method necessary. Implementation of the resume method is
therefore optional and is only necessary if, in addition to the lock for the active instance, other locks have to
be added in the same context for durable locks (as described above). This can therefore be considered an
exception.
To connect to/disconnect from a draft’s enqueue context before/after acquiring enqueue locks, the methods
attach( ) and detach( ) of framework class /BOBF/CL_LIB_ENQUEUE_CONTEXT are used – as
demonstrated in the implemented example below:
Code Sample
The following code sample demonstrates how you can implement the resume method (from /BOBF/
IF_FRW_DRAFT) that is used to keep the application-specific data of a draft instance in case the enqueue
context has been lost.
Using this code sample, you can understand the basic implementation steps of handling enqueue context for
drafts in stateless programming model.
The following call returns an instance of the enqueue context for durable locks:
DATA(enqueue_context) = /bobf/cl_lib_enqueue_context=>get_instance( ).
The enqueue context is used to call the attach( iv_draft_key ) method. This method call activates the
enqueue context in the current ABAP session. As a result, all subsequent lock operations will use this enqueue
context of the draft until detach( ) is called. Note that the importing parameter iv_draft_key should only
be the root instance keys of the current draft instance. This means in particular that it is not possible to
activate the context of a foreign business object from outside.
The specified enqueue context is also used to make locks from the legacy code durable.
With the call locks_from_legacy_code->lock_person( ), the legacy application uses function modules
to acquire its own locks on resources (in our example, on the person object).
The application calls must detach after an attach. Otherwise it will be followed by a dump. The detach( )
method deactivates the currently active enqueue context and restores the original enqueue context of the
current ABAP session. All subsequent lock operations will then use the original enqueue context of the ABAP
session. Unlike the attach( ) method, there is no draft key required for this method as an importing
parameter.
METHOD /bobf/if_frw_draft~resume.
...
*** (a) Create a durable enqueue context
DATA(enqueue_context) = /bobf/cl_lib_enqueue_context=>get_instance( ).
TRY.
LOOP AT lt_person ASSIGNING FIELD-SYMBOL(<s_person>)
WHERE personuuid IS NOT INITIAL.
*** (b) Attach the specified enqueue context
enqueue_context->attach( <s_person>-root_key ).
TRY.
*** (c) Activate locks in legacy code
locks_from_legacy_code->lock_person( <s_person>-personuuid ).
CATCH cm_my_message INTO DATA(lm_exception).
lm_exception->set_origin_location( is_location = VALUE #(
node_key = is_ctx-node_key
key = <s_person>-key
attributes = lt_attributes
) ).
eo_message->add_cm( lm_exception ).
INSERT VALUE #( key = <s_person>-root_key )
INTO TABLE et_failed_key.
ENDTRY.
4.4 Messages
This topic describes the message concept for stateless applications that is part of the ABAP application
infrastructure.
There are a lot of situations in the life cycle of an application in which messages play a crucial role. For example,
incorrect input from the end user detected in validation as faulty input or as invalid data entry, is one reason to
send corresponding feedback to the user so that a correction can be made.
Messages can be created during the execution of the application logic, such as in an action, a validation, or a
determination. They arise during the execution of these operations to inform the end user about success,
problems, or even failure.
At the technical level, messages are returned to the consumer using message containers. The message
container is returned by the application logic by assigning the reference to the exporting parameter
EO_MESSAGE.
Signature of /BOBF/IF_FRW_VALIDATION->EXECUTE
importing ...
raising ...
The validation may return state or transition messages (see also section Message Types below) to inform the
consumer about any issues. The behavior, however, depends on the state of the business object’s instance:
For draft instances, it is possible to return both STATE and In draft-enabled applications, it is not possible to create
TRANSITION messages. messages with lifetime STATE for active instances. In this
case, a short dump occurs.
Messages returned by a validation are not able to prevent active instances from beeing saved nor can they
reject activations of draft instances. This is only possible using failed keys. An instance is considered invalid
when at least one failed key is raised by at least one of the executed consistency validations, that is, when the
exporting parameter et_failed_key of the EXECUTE method (of a validation, an action, or a determination)
contains the key of the instance.
If the issue detected by the validation requires an action from the consumer to make the instance consistent, a
save of the active instance (or an activation of the draft instance) can be rejected.
If et_failed_key contains keys of draft instances, acti If et_failed_key contains keys of active instances,
vation of the draft is prevented using the draft consistency changes cannot be commited to the database.
status. More on this: Draft Consistency [page 40]
The message concept of the ABAP application infrastructure is based on ABAP class-based messages (CM
classes). That means that each individual message is an instance of an ABAP exception class. As depicted in
the figure below, message-related classes inherit from /BOBF/CM_FRW as the superclass.
The super class /BOBF/CM_FRW already provides all basic features of the message concept of the ABAP
application infrastructure. These features can be used to implement application-specific message-related
exceptions.
Remember
To keep an overview, it is recommended that you create your own message-related exception class for each
set of messages that are related to each other. Each exception class can include multiple messages.
Attributes of Messages
Whenever a message is issued, a new object of the message-related exception class is created. When a
message is created, for example in a validation’s EXECUTE method, the attributes of this object must be
specified.
Severity values are defined as constants in /BOBF/CM_FRW; they are used to indicate the
message as ERROR, WARNING, SUCCESS, or INFORMATION.
Symptom values are used to automatically determine how to deal with the message; they
are defined as constants in /BOBF/IF_FRW_MESSAGE_SYMPTOMS.
LIFETIME Specifies the message type, of either a transition message or a state message
Messages with lifetime value TRANSITION are just returned to the consumer; they do not
appear again in subsequent round-trips (fire and forget semantics).
Messages with lifetime value STATE (valid for draft instances only) are returned to the con
sumer and also persisted on the database (durable messages). They are available in subse
quent round-trips (including read operations) without re-executing the business logic that
created the message until the message is invalidated.
This attribute points out the business object, node, instance key, and attribute referred by
the message.
Note
This specifies that the referred attribute has a red border on a Fiori UI.
Note
If necessary, additional attributes can be created, for example to pass specific values for the messages.
Message Types
Depending on the value of the lifetime parameter of validations, there are two different message types
available:
● Transition messages – Events that are related to the consumer’s request or a temporary system state and
hence do not need to be persisted
Transition messages remain in the message container and are passed to the consumer by the standard
BOPF message channel. If the consumer repeats the same request later on, it might happen that the issue
will not occur any more. This kind of message follows the fire and forget semantics.
A common way to visualize transition messages is a message toast that appears only briefly on the user
interface. More on this: Message Toast
Invalidation of Messages
State messages are automatically stored in the backend until the activity that created the message for a
certain instance is called again without this message beeing created again. Therefore, state messages need to
be deleted if they are not valid anymore.
From the runtime perspective, the second point becomes true if the check logic that raised the persisted
message earlier is re-executed.
Example
A message regarding an invalid business partner ID becomes invalid as soon the corresponding validation
CHECK_VALID_ID is re-executed. The validation either creates the same message again, if the ID is still invalid
or the check is successful and the message is not raised again.
Code Sample
The following code sample demonstrates how both messages and failed keys originate from the application
logic and how they are forwarded to the application framework. The starting point is the implementation of a
consistency validation that is used in a sales order application to check whether the year entries (start_year
and end_year) specified by the end-user are valid or not.
Using this code sample, you can already see the basic process of handling messages during execution of
business process operations:
This container object is used to collect the messages that originate from the implementation of an action,
determination, or validation (as in the listing below).
The actual check whether the year entered by the end user is valid takes place in an IF statement. If the data
entry for a particular node instance is incorrect or invalid, then its technical key is added to the key table
et_failed_key.
The new message container eo_message provides access to all (class-based) messages that are issued during
a roundtrip. Each individual message that is created as an instance of the message class cm_my_message is
finally added to the message container in the call eo_message->add_cm( ).
METHOD /bobf/if_frw_validation~execute.
...
*** Constants interface of the generated business object: if_my_bo_c
DATA(lt_attributes) = VALUE stringtab( ( if_my_bo_c=>sc_node_attribute-root-
start_year )
( if_my_bo_c=>sc_node_attribute-root-
end_year ) ).
*** (a) Create a message container
eo_message = /bobf/cl_frw_message_factory=>create_container( ).
*** (b) Retrieve relevant data and return failed keys
io_read->retrieve(
EXPORTING
iv_node = is_ctx-node_key
it_key = it_key
it_requested_attributes = lt_attributes
IMPORTING
et_data = <t_data>
et_failed_key = et_failed_key
).
...
LOOP AT lt_data ASSIGNING FIELD-SYMBOL(<s_data>).
*** (c) Check whether the entered data is valid
IF <s_data>-end_year IS NOT INITIAL AND <s_data>-start_year > <s_data>-
end_year.
INSERT VALUE #( key = <s_data>-key ) INTO TABLE et_failed_key.
*** (d) Add new messages to the message container
eo_message->add_cm( NEW cm_my_message(
textid = cm_my_message=>invalid_start_end_year
start_year = <s_data>-start_year
end_year = <s_data>-end_year
severity = cm_my_message=>co_severity_error
lifetime = cm_my_message=>co_lifetime_state
ms_origin_location = VALUE #(
bo_key = is_ctx-bo_key
node_key = is_ctx-node_key
key = <s_data>-key
attributes = lt_attributes
)
) ).
ENDIF.
ENDLOOP.
ENDMETHOD.
A validation is an entity of a business object node that is triggered in certain situations to check various aspects
of a given set of node instances. It is used to validate whether a set of node instances is consistent.
Remember
Validations never modify any node instance data but they do return the messages and keys of failed
(inconsistent) node instances.
Validations check whether an active or draft node instance of business object is consistent with respect to the
consistency criteria imposed by the business requirements. Such validations are called at predefined points
within the BO transaction cycle to ensure that BO nodes are persisted in a consistent state. These points can
be configured for validations for both active and draft business objects. Each such validation configuration
contains a trigger condition that is checked by BOPF runtime at several times during the transaction. If the
trigger condition is fulfilled, the consistency validation is executed. Otherwise, if there are inconsistent node
instances, a consistency validation behaves in one of the following ways:
● The validation sends messages to the consumer – for both active and draft instances
● The validation sends messages to the consumer and prevents the transaction from being saved until the
inconsistency is corrected - for active instances
● The validation sends messages to the consumer and changes the draft consistency status – for draft
instances.
Example
The CUSTOMER_INVOICE business object may contain multiple validations to check whether the items of an
invoice are in a consistent state. For example, one consistency validation checks whether the quantity and the
price of each item are defined. Another validation checks whether the address of the buyer is valid. If it is not,
the consistency validation prevents the transaction from being saved to ensure that only consistent invoice
instances can be saved.
Implicit Validations
As a developer, you have the option of configuring the trigger condition for validation. If this condition is
fulfilled, the BOPF runtime automatically executes the validation. We call this implicit validation.
This kind of implicit validation is based on the configuration of the trigger condition that is defined for the
requested business object’s node. The trigger condition describes the node (called request node) and the kind
For each request node, independently, the triggers are configured to decide on which kind of change the
validation will be automatically executed. For validations, these change operations are:
Remember
Note that validation trigger on Delete only makes sense for sub nodes (with respect to the node where
the validation is defined). A deleted instance of a node does not exist anymore at this point in time and
cannot be validated. Therefore, the trigger on Delete for the same node or the parent node will not
execute a validation. This fact is taken into account when you check the BO by issuing a corresponding
warning message.
Remember
At least one of these operations must be flagged for each request node. Create and Update are flagged by
default.
Example: If an instance of node I_AIVS_MDBU_ARTISTTP from the figure above is created or updated, the
validation is automatically invoked by the BOPF infrastructure.
The execution of the validation on draft instances is done im In the case of a stateless session, the execution of the valida
mediately after the modification. tion on active instances is delayed when the transaction is
saved (instead of being executed immediately after modifi-
cation).
In the current release, the BOPF infrastructure implicitly trig In the case of a stateless session, the execution of the valida
gers PREPARATION in cases where the ACTIVATION action tion on active instances is delayed from immediately after
is called by the consumer. modification to when the transaction is saved (instead of be
ing executed immediately after modification).
In addition to implicit consistency validations, a consumer (for example, the UI) may explicitly run validations
(explicit validation).
To explicitly trigger the validation execution, the consumer To explicitly trigger the validation execution, the consumer
can invoke the PREPARATION action for a draft instance at can invoke the CHECK_CONSISTENCY, CHECK_AND_DE
any time during a transaction cycle. TERMINE on an active instance at any time during a transac
tion cycle.
Related Information
An action is an entity assigned to an individual node of a business object that is used to implement a service
(operation or behavior) of the business object.
You can use the RELEASE action to change the status of an invoice instance of the CUSTOMER_INVOICE
business object. As a result of this action execution, the status of the invoice can be set to RELEASED. The
following are other examples of an action:
● COPY SHEET
● PUBLISH SALES_QUOTE
● SET TO PAID SALES_ORDER
For an action to be executed, the corresponding triggers are required. Actions are called actively by one of the
following:
The user can perform an action on one or more node instances, or on no instance (static action) at all. For this
purpose, you can assign the instance multiplicity to an action. The action’s multiplicity defines how many node
instances the action can operate on during one action call. You can choose the following cardinality types for
actions:
In addition, you can configure each action with an exporting type. Using the exporting type parameter, you can
specify whether the action is able to return data to the caller during the action execution and if so what kind of
data.
● None - This default option indicates that the action does not return any data to the consumer, even if a
related action can cause changes to the business object.
● Type - This option allows the action to return a data table defined by the row type entered in the field
Exporting Parameter Structure and the corresponding table type entered in the field Exporting Parameter
Table Type.
● Node - This option allows the action to return instances of a (foreign) node that is defined by the field
Exporting Parameter Node and Exporting Parameter BO.
When implementing your own custom actions, you must first add a new action to the corresponding BO node
and the implement the action logic. The action logic is encapsulated within a global ABAP class that
implements the corresponding action interface /BOBF/IF_FRW_ACTION.
When calling an action, the consumer must provide the following specifications:
● The key of node instances on which the action operates. (This specification only applies when the action
operates on one or more instances.) An action can only be performed with exactly the number of instances
that is configured in the multiplicity of the action (see section above).
Note
To prevent an action from operating on certain specific instances, you can define an action validation.
Note
In general, an action can have multiple importing parameters, such as multiple structure components
(but always of one structure!), that the consumer passes to the implementation class at runtime. All
parameters are included in a structure known as a parameter structure.
Related Information
In the ABAP application infrastructure, a determination is an entity of a business object node that is used to
provide functions that are automatically executed as soon as a certain trigger condition is fulfilled. A
determination is triggered internally on the basis of changes made to the node instance of a business object.
The trigger conditions are checked by the ABAP application infrastructure at different points during the
transaction cycle, depending on the determination times and the changing operations on the relevant node
instances. For each determination, it is necessary to specify both the points in time and the changes that form
the trigger condition. Changes can include creating, updating, deleting, or loading node instances. As a
developer, you can implement your own custom determination primarily to compute data that is derived from
the values of other attributes. The determined attributes and the determining attributes of the trigger
condition either belong to the same node or to different nodes.
Example
If there is a change to the quantity of multiple products (items) in an invoice object instance, the amount
attribute (the overall price) for all relevant products has to be calculated again. To calculate this amount
automatically, you have to extend the standard change process for the invoice business object instances using
a custom determination. The determination can then react to the creation, modification, deletion, or loading of
an invoice item by deriving new values for the amount field. For such an example, the solution might look as
follows:
After the quantity of invoice items is changed, the trigger conditions of the CALCULATE_ITEM_AMOUNT
determination and the CALCULATE_TOTAL_AMOUNT determination are both fulfilled. The
CALCULATE_ITEM_AMOUNT determination calculates the amount of the changed item (price x quantity),
whereas the CALCULATE_TOTAL_AMOUNT determination sums up the amounts of all items to the total
amount of the invoice.
Depending on the use case in question, the ABAP application infrastructure checks the triggers of a
determination at several points during the transaction cycle.
A determination time defines at what time in the transaction cycle the trigger condition of that determination
should be evaluated. For example, the re-calculation of the invoice amount should take place every time after a
modification is performed (category: After Modify), but only if there are instances of the ITEM node that were
updated (trigger: Update).
The following list shows which trigger operations are evaluated at which determination times (categories):
The determination time and the triggers defines the trigger condition
Trigger >
------------------------
-------
React on check X
and determine
Determination Dependencies
If, in the example above, you do not define any dependencies between the determinations, the system might
calculate the total amount before the item amount. Therefore, you must specify the
CALCULATE_ITEM_AMOUNT determination as a predecessor of the CALCULATE_TOTAL_AMOUNT
determination.
Example
The following dependency is defined in such a way that the item amount is calculated before the total amount.
4, 1, 3, 2, 5 (for example, the determination DET 2 is always executed before the execution of DET 5)
1, 2, 5, 4, 3 (for example, DET 1 is always executed before the execution of DET 2).
When implementing your own custom determination, you first must add a new determination to the
corresponding BO node and then implement the determination logic.
The determination logic is encapsulated within an ABAP class that implements the determination interface /
BOBF/IF_FRW_DETERMINATION.
Related Information
Extending the Implementation for Creating Sales Order Items [page 138]
Contents
Developing List Reporting Apps with Search and Analytical Capabilities [page 67]
Introduction
Starting from the elementary list reporting scenario that was introduced in the Getting Started section, you
may want to add some further list reporting functions. For example, if your table or list contains many rows, it
becomes difficult for end users to find the information they need. To facilitate finding the desired information,
you can provide selection fields (filters) to specify the range of information that the end user is looking for. In
addition, you may want to specify the positioning of columns or prioritize, or even hide, specific fields in your
table or list, or even enrich the presentation of data with appragation capabilities.
This is implemented using specific CDS annotations, which you – as a Fiori app developer – add to the source
code of the respective CDS view. A CDS annotation (in short: annotation) adds metadata to the view that
expands the syntax options of SQL.
In this development scenario, you will use different types of CDS annotations:
● Core annotations - can be specified in the source code of any ABAP CDS object and are evaluated by
ABAP runtime environment.
● UI annotations - allow you to focus OData UI vocabulary on usage patterns of data in UIs representing
certain semantic views of business data. The UI annotations used are evaluated by the SADL framework,
which means that SADL translates CDS annotations into the corresponding OData annotations.
● Search annotations - allow you to define search fields as filters or . The annotations used are also
evaluated by the SADL framework.
● Analytics annotations - provide data elements with aggregation behaviour in analytical scenarios.
Architecture Overview
Architecture components in a list reporting scenario that expands the data definition with metadata
Related Information
Starting Point
Let us assume you have already created a DDL source as a development object and implemented it as simple
data model for EPM sales order items - as shown in the listing below.
@AbapCatalog.sqlViewName: 'ZDEMO_SOI_ADV'
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Advanced List Reporting for Sales Order Item'
@OData.publish: true
The source code above defines quite a simple CDS view called ZDEMO_CDS_SalesOrderItem_A. This view is
implemented by means of a query for performing a SELECT statement, where the predefined CDS view
SEPM_I_SalesOrderItem_E (that originates from the EPM demo application) is used as the data source. The
select list includes a set of fields that are relevant for the new sales order item consumption view. The KEY
elements in the selection list are used to define the key field semantic of the CDS view.
This topic demonstrates how you can expand the syntax of the CDS view to include metadata with the aim of
providing some additional list reporting capabilities.
You have the option to work with a title in your result list. For this, add the @UI.headerInfo annotation to the
CDS view and specify the header information in singular form for a single instance (single sales order item) and
in plural form for multiple instances of sales order items.
Preview:
If a CDS view is annotated as @Search.searchable, the UI runtime automatically takes this is into
consideration, so that no additional UI annotations are required to expose a standard search field. However, for
a meaningful search, at least one field must be defined as the default search field by annotating this field as
@defaultSearchElement: true. The search is then initiated solely effected by those fields that are defined
as default search fields. In the listing below, the ProductCategory is defined as the default search field.
@Search.searchable: true
define view ZDEMO_CDS_SalesOrderItem_A as
...
@Search.defaultSearchElement: true
Item.Product as Product,
...
To facilitate finding the desired data, you can provide the standard filter for the list reporting UI.
You can use the following UI annotations to enable specific elements for selection, for example, when providing
a filter bar:
The first filter allows the end user to search for Sales Order IDs. As the second filter, the customer’s Company
search field is defined. In addition, the Company field should be considered as the default search field in the
standard search filter.
Note
@UI.selectionField.position: 10
key Item.SalesOrder as SalesOrderID,
...
@UI.selectionField.position: 20
@Search: { defaultSearchElement: true, fuzzinessThreshold: 0.7 }
Item._SalesOrder._Customer.CompanyName as CompanyName,
...
Preview:
Now you can specify which field should be displayed in the list report and at which position.
To define the order of fields in the UI, you can use the position property of dataField-like annotations. Only
the positioning order is relevant, so you can use any decimal number as the value for the positioning property.
To define the priority of elements, you can use the importance property of dataField-like annotations. This
information, in particular, is relevant for adaptive UIs. If an UI is displayed on a small screen, elements with low
priority can automatically be hidden. To define importance, you can choose the following values:
● #HIGH
● #MEDIUM
● #LOW
● None (Default)
It is not required for the ItemPosition field to appear as a separate field in the result Sales Order list.
Therefore, this field should be hidden in the list and therefore not available for the personalization settings
dialog.
...
@UI.hidden: true
key Item.SalesOrderItem as ItemPosition,
...
In the list, the Sales Order ID field should get a specific label (Sales Order) and be displayed at the first
position within the result list.
...
@UI.lineItem: { importance: #HIGH, label: 'Sales Order', position: 10 }
key Item.SalesOrder as SalesOrderID,
...
The order of fields is continued with currency and both amount fields:
...
@UI.lineItem.position: { position: 40, importance: #HIGH }
Item.GrossAmountInTransacCurrency as GrossAmount,
@UI.lineItem.position: 50
Item.NetAmountInTransactionCurrency as NetAmount,
@UI.lineItem.position: 60
Item.TaxAmountInTransactionCurrency as TaxAmount
...
...
@UI.lineItem.position: 20
Item._SalesOrder._Customer.CompanyName as CompanyName,
...
...
@UI.lineItem.position: 30
Item.Product as Product,
...
Preview:
It is not required for the currency field to appear as a separate field in the result list. The currency code has only
to be displayed in connection with the amount data instead. This is implemented by the annotation
@Semantics.currencyCode: true. The annotation @Semantics.amount.currencyCode:
'CurrencyCode' defines each amount element as a currency field.
The @Aggregation.Default: #SUM annotation is used for analytical capabilities: The annotated amount
fields are specified as so-called measures, that is, fields that can be aggregated.
Note
...
@Semantics.currencyCode: true
Item.currency_code as CurrencyCode,
...
@Semantics.amount.currencyCode: 'CurrencyCode'
@Aggregation.Default: #SUM
Item.GrossAmountInTransacCurrency as GrossAmount,
...
@Semantics.amount.currencyCode: 'CurrencyCode'
@Aggregation.Default: #SUM
Item.NetAmountInTransactionCurrency as NetAmount
...
@Semantics.amount.currencyCode: 'CurrencyCode'
@Aggregation.Default: #SUM
Item.TaxAmountInTransactionCurrency as TaxAmount,
...
For more detailed information about analytical annotations and their interpretation, please refer to Using
Aggregate Data in SAP Fiori Apps [page 263].
In order to display an amount in unitary currency, ABAP CDS provides the currency conversion function. In our
example, EURO is specified as the target currency. The value 'EUR' is passed to the formal paramter
target_currency to be linked with the amount value of the conversion function. In the case of an error, for
example when a currency does not exist, the result is set to null value.
...
@Semantics.currencyCode: true
cast( 'EUR' as abap.cuky ) as TargetCurrency,
@Semantics.amount.currencyCode: 'TargetCurrency'
CURRENCY_CONVERSION(
amount => Item.GrossAmountInTransacCurrency,
source_currency => Item.TransactionCurrency,
target_currency => cast( 'EUR' as abap.cuky ),
exchange_rate_date => cast( '20160101' as abap.dats ),
Preview:
The aggregated fields display the sum for the traget currency
The resulting source code that includes the metadata for the CDS view looks like this:
@AbapCatalog.sqlViewName: 'ZDEMO_SOI_ADV'
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Advanced Reporting for Sales Order Items'
@Search.searchable : true
@OData.publish: true
@UI.headerInfo:{ typeName: 'Sales Order Item', typeNamePlural: 'Sales Order
Items' }
define view ZDEMO_CDS_SalesOrderItem_A
as select from SEPM_I_SalesOrderItem_E as Item
{
@UI.lineItem: { label: 'Sales Order', position: 10, importance: #HIGH }
@UI.selectionField.position: 10
@UI.identification: { label: 'Sales Order', position: 10, importance:
#HIGH }
@UI.hidden: true
key Item.SalesOrderItem as ItemPosition,
@UI.lineItem.position: 20
@UI.selectionField.position: 20
@Search: { defaultSearchElement: true, fuzzinessThreshold: 0.7 }
@UI.identification: { label: 'Company Name', position: 20, importance:
#HIGH }
Item._SalesOrder._Customer.CompanyName as CompanyName,
@UI.lineItem.position: 30
@Search.defaultSearchElement: true
@UI.identification.position: 30
Item.Product as Product,
@Semantics.currencyCode: true
@UI.lineItem.position: 50
@Semantics.amount.currencyCode: 'CurrencyCode'
@UI.identification.position: 50
@DefaultAggregation: #SUM
Item.NetAmountInTransactionCurrency as NetAmount,
@UI.lineItem.position: 60
@Semantics.amount.currencyCode: 'CurrencyCode'
@UI.identification.position: 60
@DefaultAggregation: #SUM
Item.TaxAmountInTransactionCurrency as TaxAmount,
Item.ProductAvailabilityStatus as ProductAvailabilityStatus,
@Semantics.currencyCode: true
cast( 'EUR' as abap.cuky ) as TargetCurrency,
@UI.lineItem:{ label: 'Gross Amount in EUR', position: 45 }
@DefaultAggregation: #SUM
@Semantics.amount.currencyCode: 'TargetCurrency'
CURRENCY_CONVERSION(
amount => Item.GrossAmountInTransacCurrency,
source_currency => Item.TransactionCurrency,
target_currency => cast( 'EUR' as abap.cuky ),
exchange_rate_date => cast( '20160101' as abap.dats ),
error_handling => 'SET_TO_NULL' ) as
ConvertedGrossAmount
To make the CDS view ready for consumption, you have to activate the resulting OData service in the SAP
Gateway hub.
The activated service is part of the Service Catalog in the SAP Gateway.
Introduction
Let us assume you have to develop a completely new transactional application for SAP Fiori UI in such a way
that the persistence model does not provide any GUIDs as primary keys to the consumer, but application-
specific semantic keys.
In this chapter, we will develop - step by step - quite a simple sales order application, starting with the creation
of a basic persistence model. We will then define a normalized data model, followed by the provision of a
service-specific consumption view. After this, we are going to build a Fiori UI using Smart Templates as Fiori
building blocks and test the resulting app within the SAP Fiori Launchpad. In our final step, we will extend the
application’s business logic with actions that are implemented with the help of BOPF API.
As with any other business application, a set of database tables and other Dictionary objects defines the
persistence model of a transaction application. As a data source for a business object to be generated, a
database table needs to be provided for each so-called business object CDS view (also referred to as business
object views). Generally, business object views are normalized CDS views that define the hierarchy of entities
by using associations and @ObjectModel annotations. A business object view is defined on top of the
underlying database table or the CDS view and exposes all elements that are defined in the SELECT list,
including the key elements that correspond to the primary keys of the underlying database table. In the
transactional scenario of the programming model for SAP Fiori, the business object view is required for
business object generation on the basis of the BOPF framework.
A consumption CDS view (also referred to as consumption view) allows the consumption of a business object
view in a different manner by different OData services. Each service-specific view is defined on top of a
business object view and exposes its fields. A consumption view enhances the data model with metadata,
additional associations, or even with transient fields that fit to a given consumption use case. In particular, the
consumption views are used to enhance the data model with UI-specific annotations for later consumption in
Fiori UIs.
Contents
For our sample scenario, we will first create a suitable database table for Sales Order header data using ABAP
Dictionary tools and then use this as a data source for a new data model.
In order to be closer to the classical data model of the Suite, we introduce normalized data models -defined on
top of the respective database tables - that have already been shipped as part of the EPM sample data model.
These models expose semantic primary keys that consist of one or more fields. To be able to access data from
other entities, a set of associations will be defined in the new data model.
After activation of the data definition, the BOPF runtime generates a corresponding business object.
Procedure
Sales order data can be distributed generally across multiple database tables: a table for the sales order
(header data), a table for business partners, or for currency and status information. With the provision of
normalized persistence, each individual database table serves for arranging data into logical groupings such
that each one describes a small part of the whole. In the context of business applications, each table field
corresponds to an attribute of the business object that is represented by the entire database table. Each table
row represents a unique instance of that business object and must be different in some way from all other rows
(that is, no duplicate rows are possible).
To provide data persistence for our sample Sales Order scenario, we assume that you...
● Have the standard developer authorization profile to create ABAP development objects with ABAP
Development Tools.
● Reuse the data elements from EPM sample data model (SNWD_*) when creating table fields for Sales
Order (header) table.
● Access related business data from associated views or tables that originate in EPM sample data model.
For our sample scenario, we will first create a suitable database table (ZTAB_SO) for sales order data using
ADT ABAP Dictionary tools and then use this table as a data source for a new CDS-based data model.
BUSINESSPARTNER SNWD_PARTNER_ID
CURRENCYCODE SNWD_CURR_CODE
GROSSAMOUNT SNWD_TTL_GROSS_AMOUNT
NETAMOUNT SNWD_TTL_NET_AMOUNT
BILLINGSTATUS SNWD_SO_CF_STATUS_CODE
OVERALLSTATUS SNWD_SO_OA_STATUS_CODE
.INCLUDE /BOBF/S_LIB_ADMIN_DATA
Tip
The standard administration data, such as the respective user or the time of creation, are included in the
table by means of a predefined BOPF structure /bobf/s_lib_admin_data.
Procedure
Since SAP NetWeaver AS for ABAP 7.52 SP00, you can create and work with database tables in ABAP
Development Tools (ADT) using the source-based editor.
1. Open the source-based ABAP Dictionary editor in ADT and create the database table ZTAB_SO with the
fields as they are listed below. For further information, see:
2. Edit the database table as follows:
Using the time-proven ABAP Dictionary tools, you created and activated a database table for Sales Orders
(ZTAB_SO) as a part of normalized data persistence.
On the basis of the table ZTAB_SO we will generate a corresponding business object. Each table field
corresponds to an attribute of the Sales Order business object (to be created) represented by the entire table.
Related Information
Database Tables
This topic demonstrates how you can implement a Business Object view to provide a normalized data model
for a simple Sales Order application.
Each business object view must contain a specific set of @ObjectModel CDS annotations, indicating - for
example - the root of the given entity. The business object view of the root entity needs additional CDS
annotations in order to trigger the automatic generation of the respective BOPF business object, which is
named after the respective business object view.
@ObjectModel.modelCategory: Serves for semantic categorization only (the CDS view rep
#BUSINESS_OBJECT resents a business object) in the context of the Virtual Data
Model (VDM). The model category is an optional annotation
and has no runtime effect.
@ObjectModel.compositionRoot: true Defines the root of the compositional hierarchy for the busi
ness object to be created
In addition, the following annotations are required for all editable entities (including the root entity):
@ObjectModel.writeActivePersistence: Specifies the database table or the database view for storing
'<database_table/view> BO data changes that result from transactional behavior
● The DDL-based data definition, as the corresponding development object, is already created in the ABAP
package of your choice. In our case, both the data definition and the business object view are named as
ZDEMO_I_SALESORDER_TX.
● The persistence model is already defined. In particular, you have already created and activated the
database table ZTAB_SO that serves as data source for the business object view.
Caution
Whenever the table field names and the corresponding element names in the business object view are
different (except for camel-case), this will cause problems when activating the view. For further
information on how to avoid such an issue, see also: Mapping CDS View-Elements onto Table Fields
[page 286]
● The key in the data model corresponds to the primary key (SALESORDER) of the underlying database table.
The following listing provides you with the implementation of a rather elementary Sales Order data model,
where the database table ZTAB_SO is defined as the data source for the corresponding CDS view
ZDEMO_I_SalesOrder_TX (camel case notation!). In addition, the table ZTAB_SO also serves as a storage
place for business object data changes that result from transactional behavior. Therefore, this table is specified
in the @ObjectModel.writeActivePersistence annotation. To be able to access business data from other
entities, a set of associations is defined as part of the data model. These associations refer to CDS views that
are already provided as part of the EPM data model.
@AbapCatalog.sqlViewName: 'ZDEMO_I_SO'
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Sales Order for transactional app'
@ObjectModel.modelCategory: #BUSINESS_OBJECT
@ObjectModel.compositionRoot: true
@ObjectModel.transactionalProcessingEnabled: true
@ObjectModel.writeActivePersistence: 'ZTAB_SO'
@ObjectModel.createEnabled: true
@ObjectModel.deleteEnabled: true
@ObjectModel.updateEnabled: true
as select from ZTAB_SO as SalesOrder -- the sales order table is the data
source for this view
{
key SalesOrder.salesorder as SalesOrder,
@ObjectModel.foreignKey.association: '_BusinessPartner'
SalesOrder.businesspartner as BusinessPartner,
@ObjectModel.foreignKey.association: '_Currency'
@Semantics.currencyCode: true
SalesOrder.currencycode as CurrencyCode,
@Semantics.amount.currencyCode: 'CurrencyCode'
SalesOrder.grossamount as GrossAmount,
@Semantics.amount.currencyCode: 'CurrencyCode'
SalesOrder.netamount as NetAmount,
@ObjectModel.foreignKey.association: '_BillingStatus'
SalesOrder.billingstatus as BillingStatus,
@ObjectModel.foreignKey.association: '_OverallStatus'
SalesOrder.overallstatus as OverallStatus,
/* Associations */
_BusinessPartner,
_Currency,
_BillingStatus,
_OverallStatus
}
After ensuring that the syntax of the CDS view is complete and correct, activate the data definition (as the
corresponding development object).
As a result of successful activation, the BOPF runtime creates a business object ZDEMO_I_SALESORDER_TX
(upper case notation!) that is named after, and is stored in, the same package as the underlying CDS view, in
our case: ZDEMO_I_SalesOrder_TX (camel case notation!). The decorator within the editor ruler indicates
that the generation process has been successful. If you move the cursor over the decorator, an info screen
informs you that the business object is generated for the CDS view. In addition, the info screen provides you
with a link to the business object editor.
On the entry page of the BO editor, you can identify the Constants Interface that has been generated together
with the business object.
Remember
Constants Interface is an ABAP interface that is dedicated to a specific business object. The interface
includes constants for each business object’s entity like nodes, attributes, actions and so on. We will be
using it later on when we add an action to the business object generated.
If you now choose Go to the ROOT node, you can view some more details at the entity level of the business
object. You must know these when you proceed to use the BOPF API - for example, when implementing an
action. Here you can find the names of the ABAP Dictionary objects that have been generated together with the
business object.
Starting from your ABAP Development Tools (ADT) client, you can test the generated business object in the
integrated BOPF test environment. Using the BOPF test environment, you can test the core services such as
creating, updating, or deleting business object instances without writing any test code.
Procedure
To launch the BOPF test environment, select the node of the generated business object in the Project Explorer
tree, open the context menu, and choose Run As Test Environment .
The BOPF test shell appears in the SAP GUI window and opens the test session.
To create a new node instance, select the corresponding node in the Node Instances navigation pane and click
the (Add Node Instance) push button from the toolbar of the editor pane – as depicted in the figure below.
Finally you have the option to save your Sales Order data by choosing Save from the toolbar. The data is saved
in the database table that is assigned to the node of the Sales Order business object.
Results
You can either save the changes you have made or discard them. To finish a test session, close the test
environment.
Within a few minutes you have verified that the generated sales order business object works correctly, without
writing any test code
Based on the Sales Order BO view, we are now going to implement the data model for consumption with the
help of the consumption view.
Consumption View
The ObjectModel annotations that are used in the consumption view provide transactional related aspects of
the business data model.
@ObjectModel.transactional Indicates that transactional access to the consumption view is delegated to the
ProcessingDelegated: true transactional runtime of the underlying view (which is annotated with @Object
Model.transactionalProcessingEnabled: true).
In addition, the following annotations are required for all editable entities (including the root entity):
@ObjectModel.createEnabled Allows the end user to create new business object instances
: true
@ObjectModel.updateEnabled Allows the end user to update existing business object instances
: true
Remember
CDS rule: Remember to double-maintain the annotations that have the VIEW scope. In CDS views, only the
annotations with ELEMENT and ASSIOCIATION scope are inherited from the business object view.
Prerequisites
● The DDL-based data definition, as the corresponding development object, is already created. In our case,
the DDL data definition and the CDS view are named ZDEMO_C_SALESORDER_TX and
ZDEMO_C_SalesOrder_TX respectively.
● The business object CDS view that you implemented in the previous step serves as the data source for the
consumption view.
● The key in the data model in the consumption view corresponds to the primary key of the underlying
database table.
In this implementation, the business object view is the data source of the consumption view
ZDEMO_C_SalesOrder_TX. The @ObjectModel.transactionalProcessingDelegated: true
annotation indicates that transaction requests to the consumption view are delegated to the underlying
business object view.
To expose the data model and its metadata to the OData service, the consumption view is annotated with
@OData.publish: true.
The SELECT list includes a set of fields that are relevant for consumption in a user interface (UI). The key is
specified as a semantic key SalesOrder. This is implemented by the annotation
@ObjectModel.semanticKey: 'SalesOrder'.
@AbapCatalog.sqlViewName: 'ZDEMO_C_SO'
@AccessControl.authorizationCheck: #NOT_REQUIRED
@ObjectModel.semanticKey: 'SalesOrder'
@ObjectModel.transactionalProcessingDelegated: true
@ObjectModel.createEnabled: true
@ObjectModel.deleteEnabled: true
@ObjectModel.updateEnabled: true
@OData.publish: true
@UI.lineItem.position: 10
@UI.identification.position: 10
key Document.SalesOrder,
@UI.lineItem.position: 20
@UI.identification.position: 20
Document.BusinessPartner,
Document.CurrencyCode,
@UI.lineItem.position: 50
@UI.identification.position: 50
Document.GrossAmount,
@UI.lineItem.position: 60
@UI.identification.position: 60
Document.NetAmount,
@UI.lineItem.position: 30
@UI.selectionField.position: 30
@UI.identification.position: 30
Document.BillingStatus,
@UI.lineItem.position: 40
@UI.selectionField.position: 40
@UI.identification.position: 40
Document.OverallStatus,
Document._Currency,
Document._BillingStatus,
Document._OverallStatus
● The actual service artifact with the technical name <CDS_VIEW>_CDS. You can find it at SAP Gateway
Business Suite Enablement - Service object (object type: R3TR IWSV).
● An SAP Gateway model (object type: R3TR IWMO) with the name <CDS_VIEW>_CDS.
● An ABAP class ZCL_<CDS_VIEW> (in case of local objects) or <Namespace>CL_<CDS_VIEW> (other
objects) that is used to provide model metadata to the SAP Gateway service.
All generated service artifacts are automatically added to the same ABAP package (and also to the same
transport request) as the underlying consumption CDS view.
To make your data model ready for consumption, you only have to activate the resulting OData service in the
SAP Gateway hub.
Activated OData service is listed in the Service Catalog of the SAP Gateway
Tip
To verify that the activated OData service works correctly, you can test the service.
To make sure that all parts of the application work correctly for the end user, we are now going to run the
resulting application.
Prerequisites
● The consumption view is exposed as an OData service using the so-called auto exposure approach
(@OData.publish: true).
More on this: Generating OData Service With Auto-Exposure [page 19]
Procedure
If you run the new app based on Fiori Smart Templates in the Fiori Launchpad, the resulting UI provides you
with a list of sales orders, including all fields that you exposed for consumption.
Note
Each field that results from an association’s path provides you with value help options. More on this:
You might wish to extend the scenario that was developed in the previous chapter to include additional
functions. For example, you might be interested in extending the business logic so that status changes to
individual instances of the Sales Order business object can be executed, without the end user having to switch
to edit mode. In this case, the so-called quick actions come in to play
Quick actions are “one-click” actions with optional parameters. They are used for performing an action on each
individual record without the need for the end user to switch to edit mode. For quick actions, no state needs to
be kept on the client or back-end server. A quick action triggers the business logic in the back end that is
immediately executed (in our case: written to the database. In a UI screen, the detail page (object page) might
show the data as read-only and also offer quick actions without the need to switch to edit mode.
Tip
You have the option to provide quick actions also in non-transactional areas, that is, in purely list-reporting
development scenarios.
Action implementation and action control requires business logic that is implemented on the basis of the BOPF
API. Therefore, quick actions are implemented as standard BOPF actions that are assigned to the related
business object node. At runtime, a (quick) action can modify a node instance of the assigned business object
or node instance of other associated business objects.
Context
To define the behavior of a sales order business object at runtime, we need to add a corresponding action
entity to the generated business object. For our sample scenario, we are going to create an action
SET_TO_PAID to change the status of the sales order item to PAID after a buyer pays for a product provided by
a seller.
1. To create an action of the business object generated in the step Defining the Business Object [page 79],
open the editor of this business object and select the Actions tab.
2. Then choose New to launch the New Action wizard.
3. Specify the details:
○ Name: SET_TO_PAID
○ Description: Enter a short description that describes the purpose of the action.
○ Implementation Class: Accept the name for the action class that is suggested by the wizard.
○ Instance Multiplicity: Select Single Node Instance from the list box. This option allows the action to
operate on a single sales order node instance. In other words: In the resulting app, we don’t want to
allow the end user to execute the action on a set of multiple node instances.
○ Parameter Structure: We leave this field empty since we are not going to use action parameters in our
scenario.
Results
The BOPF framework assigns the new action to the business object node and creates an action class that
implements the BOPF action interface /BOBF/IF_FRW_ACTION.
Related Information
Each action in BOPF must implement the execute method of the action interface /BOBF/IF_FRW_ACTION.
The listing below is used to implement the SET_TO_PAID action of the generated business object
ZDEMO_I_SALESORDER_TX. A consumer can use this action to mark the status of the sales order as paid.
PUBLIC SECTION.
METHOD /bobf/if_frw_action~execute.
The SET_TO_PAID action is carried out by the execute method. As in most cases, the first step within the
execute method is to retrieve relevant data of those node instances that are going to be changed. Remember,
all attributes of the root node are represented by the combined structure’s component.
For reading BO data, a data reference lt_sales_order is used, where lt_sales_order refers to the
combined table type ztdemo_i_salesorder_tx. It contains the keys and data of all node instances on which
the action should be applied. This enables you to access the root node attribute billing_status and then
set a new value P that indicates that the node instance is set to status PAID.
For each relevant node instance, the update method of the access object io_modify is called. Here the
internal table it_changed_fields is populated with attributes that are going to be updated. Like all other
entity names, the attribute names, too, are available through the Constants Interface
ZIF_DEMO_I_SALESORDER_TX_C. As result of the method call, the node instance is updated in the database.
Using the BOPF test environment, you can test not only the CRUD of business object instances, but also
execute the action (which you implemented and activated in the previous step) to check whether it runs
correctly.
Procedure
As a result of action execution, the attributes billing_status and overall_status display the new value P
(PAID).
Results
With only a few clicks, you have verified that the action works fine and you can now save the changes you have
made or discard them. To finish a test session, close the test environment.
Actions are often directly related to BO instances that you can see in a table with sales order records, for
example. End users can select as a line item (that represents a BO instance) and execute certain actions on the
selected item.
You can use the following UI annotation to expose actions to the consumer:
...
define view <CDS_VIEW> as select from <DATA_SOURCE> as .. {
@UI.lineItem: [
{ type: #FOR_ACTION, dataAction: 'BOPF:<BO_ACTION_1>', label:
'<ACTION_LABEL_1>' },
{ type: #FOR_ACTION, dataAction: 'BOPF:<BO_ACTION_2>', label:
'<ACTION_LABEL_2>' },
...
]
...
Note
The dataAction element references the technical name of an action of the BOPF. The string pattern is
BOPF:<technical name of action in BOPF>.
...
To publish the new metadata to the OData service, activate the data definition that implements the
consumption view (in our case: ZDEMO_C_SalesOrder_TX).
To make the action available for consumption in the OData service, the following configuration steps in the BO
editor are required. Otherwise, the action would be unknown in the OData consumption layer.
Procedure
1. If you have not yet already done so, open the editor of the business object (in our case:
ZDEMO_I_SALESORDER_TX) and click the Actions tab.
2. Select the action SET_TO_PAID and choose CTRL + Click to open the Action Overview.
Results
The BOPF framework assigns the configuration details to the action. As a result of this configuration
procedure, the action will be exported as an additional function to the OData consumption layer.
Again, you have the option to run the changed app based on Fiori Smart Templates in the Fiori Launchpad to
check the action execution.
If you run the app, the resulting UI screen provides you with the label Set to Paid for the new action - as shown
in the figure below.
Based on an end-to-end development example, you will, from scratch, create and implement all requisite
artifacts that combine transactional processing with draft capabilities.
Prerequisites
In addition to the general Prerequisites [page 9], the development of new transactional apps with draft
capabilities requires the following:
● ABAP Application Server as of SAP NetWeaver AS for ABAP 7.51 innovation package SP02 or higher
● Client installation of ABAP Development Tools (ADT) with the client version 2.73 or higher
Note
We recommend that you use the latest available ADT client, which can be downloaded from the public
update site.
● For draft enabling, the key of the data model must be a UUID-based key, as it is native in the BOPF
programming model
● Expert knowledge of the BOPF programming model.
Draft Support
Up to now, SAP’s transactional applications have been developed using stateful technologies, such as
Floorplan Manager (FPM) for WebDynpro ABAP or the classic Dynpro technique. These stateful applications
rely on a server session along with application buffers that can fulfill client requests (user interactions with
multiple backend round trips) until the user has saved the data changes and finished his or her work.
Let us assume that you, as the application developer have to develop a completely new transactional app for
SAP Fiori UI that also provides the draft data support. As the application developer, you may need to provide
the end user with capabilities to store changed data at any time in the backend and proceed at a later point in
time or to recover such data, even if the application client has crashed. However, this use case requires certain
additional activities to enable the draft concept for your new app.
Such an app must always be able to deal with two versions of data:
● The active data that represents the state of the business entity (sales order) that is stored in the active
persistence.
● The draft data that represents the transient state of a business entity until it is permanently stored in the
persistence layer as active data. The draft data is stored in the draft persistence until its transition to the
active data. The draft data is stored in the draft persistence until its transition to active data. As depicted in
the figure below, a draft version of the business object plays a central role in this transition.
Preview
In the first version of our example app for sales order processing, the end user is able list all sales orders
available in the system and perform all CRUD operations on sales order instances. In addition, the resulting
Fiori app provides draft-enabling capabilities.
Resulting Fiori app provides both transactional behavior and draft qualities
The extended Fiori app provides transactional behavior including draft qualities also at the level of sales order items
This new generation of applications enhances the general architecture of transactional applications through
stateless communication with the ABAP back-end server. The figure below provides an overview of the main
development objects and technologies involved when creating a transactional, draft-enabled Fiori apps based
on the new ABAP programming model.
ABAP CDS provides a data modeling infrastructure for defining and consuming semantically rich data models
in the ABAP platform starting with SAP NetWeaver AS for ABAP 7.4 SP05. CDS data models can be enhanced
at the data model level using CDS view extensions and at the metadata level using CDS metadata extensions.
ABAP CDS is a core technology within SAP S/4HANA and the ABAP development for SAP HANA in general.
[More...]
MDEs are used to define CDS annotations for a CDS view outside of the corresponding data definition. A CDS
metadata extension is always assigned to a specific layer such as core, industry, partner or customer. The use
of MDEs allows the separation of concerns by separating the data model from domain-specific semantics, such
as UI-related information for Fiori elements. [More...] [page 185]
BOPF is a framework that provides a set of generic services and functionalities to speed up, standardize, and
modularize your development of business applications. BOPF manages the entire life cycle of your business
objects and covers all aspects of your business application development. Instead of expending effort for
developing an application infrastructure, the developer can focus on the individual business logic. Using BOPF
provides you with the entire application infrastructure and integration of various components for free. This
allows you to build applications rapidly on a stable and customer-proved infrastructure. More:
When using BOPF, you have various options to add application-specific business logic:
● BOPF determinations, which are used to calculate side-effects (automatically triggered by changes).
● BOPF validations, which are consistency checks that raise messages (automatically triggered by changes).
● BOPF actions, which are named operations that can be called (usually by a button on the UI).
1. Defining the Draft Business Object for Sales Order [page 109]
2. Providing Additional Business Logic with a BOPF Determination [page 121]
3. Defining the Consumption Layer [page 124]
4. Adding UI Semantics for Consumption in Fiori UI [page 127]
5. Running the Resulting Fiori App [page 131]
6. Extending the Implementation for Adding New Sales Order Items [page 132]
7. Extending the Implementation with Value Validation [page 148]
______________________________________________________________
8. Extending the Implementation for Adding New Sales Order Items [page 132]
9. Extending the Implementation with Value Validation [page 148]
10. Extending the Implementation with an Action [page 152]
As with any other business application, a set of database tables and other ABAP Dictionary objects defines the
persistence model of a transaction application. To serve as a data source for a business object to be generated,
a database table must be provided for each business object CDS view (also referred to as a business object
views). Generally, business object views are normalized CDS views that define the hierarchy of entities by using
associations and @ObjectModel annotations. A business object view is defined on top of the underlying
database table or another CDS view and exposes all elements that are defined in the SELECT list, including the
key elements that correspond to the primary keys of the underlying database table. In the transactional
scenario of the programming model for SAP Fiori, the business object view is required for business object
generation based on the BOPF framework.
Note
In the context of draft-enablement, the concept of the business objects is (re)used to generate a draft
entity based on the BOPF business object metadata model.
Sales order data can be distributed across multiple database tables: a table for the sales order (header data), a
table for business partners, or a table for currency and status information. With the provision of normalized
persistence, each individual database table is used to arrange data into logical groupings such that each one
describes a small part of the whole. In the context of business applications, each table field corresponds to an
attribute of the business object that is represented by the entire database table. Each table row represents a
unique instance of that business object and must be different in some way from all other rows (that is, no
duplicate rows are possible).
For our sample scenario, we will first create a suitable database table (ZDEMO_SOH) for sales order header data
using ADT ABAP Dictionary tools and then use this as a data source for a new CDS-based data model.
SALESORDER SNWD_SO_ID
BUSINESSPARTNER SNWD_PARTNER_ID
OVERALLSTATUS SNWD_SO_OA_STATUS_CODE
CHANGEDAT TIMESTAMPL
CHANGEDBY UNAME
CREATEDBY UNAME
CREATEDAT TIMESTAMPL
Remember
The database table above also provides the basic administrative fields. They are used for administrative
data, which usually covers the user that has created or last changed an instance and the corresponding
timestamps. In particular, we will use the field CHANGEDAT for ETag check. In our draft scenario, the ETag
check is used to determine whether two representations of a business entity, such as an active instance
ETags play a significant role in the lock lifetime when working with draft instances of business objects. For
further information, see: Draft Entities and Durable Locks [page 46]
Sales order data can be distributed across multiple database tables: a table for the sales order (header data), a
table for business partners, or a table for currency and status information. With the provision of normalized
persistence, each individual database table is used to arrange data into logical groupings such that each one
describes a small part of the whole. In the context of business applications, each table field corresponds to an
attribute of the business object that is represented by the entire database table. Each table row represents a
unique instance of that business object and must be different in some way from all other rows (that is, no
duplicate rows are possible).
For our sample scenario, we will first create a suitable database table (ZDEMO_SOH) for sales order header data
using ADT ABAP Dictionary tools and then use this as a data source for a new CDS-based data model.
SALESORDER SNWD_SO_ID
BUSINESSPARTNER SNWD_PARTNER_ID
OVERALLSTATUS SNWD_SO_OA_STATUS_CODE
CHANGEDAT TIMESTAMPL
CHANGEDBY UNAME
CREATEDBY UNAME
CREATEDAT TIMESTAMPL
Sales order data can be distributed across multiple database tables: a table for the sales order (header data), a
table for business partners, or a table for currency and status information. With the provision of normalized
persistence, each individual database table is used to arrange data into logical groupings such that each one
describes a small part of the whole. In the context of business applications, each table field corresponds to an
attribute of the business object that is represented by the entire database table. Each table row represents a
unique instance of that business object and must be different in some way from all other rows (that is, no
duplicate rows are possible).
For our sample scenario, we will first create a suitable database table (ZDEMO_SOH) for sales order header data
using ADT ABAP Dictionary tools and then use this as a data source for a new CDS-based data model.
SALESORDER SNWD_SO_ID
BUSINESSPARTNER SNWD_PARTNER_ID
OVERALLSTATUS SNWD_SO_OA_STATUS_CODE
CHANGEDAT TIMESTAMPL
CHANGEDBY UNAME
CREATEDBY UNAME
CREATEDAT TIMESTAMPL
Remember
The database table above also provides the basic administrative fields. They are used for administrative
data, which usually covers the user that has created or last changed an instance and the corresponding
timestamps. In particular, we will use the field CHANGEDAT for ETag check. In our draft scenario, the ETag
check is used to determine whether two representations of a business entity, such as an active instance
and the corresponding draft BO instance, are the same. If the representation of the entity ever changes, a
new and different ETag value is assigned.
ETags play a significant role in the lock lifetime when working with draft instances of business objects. For
further information, see: Draft Entities and Durable Locks [page 46]
To provide data persistence for our sample sales order scenario, we assume that you...
● Have the standard developer authorization profile to create ABAP development objects with ABAP
Development Tools.
● Reuse the data elements from the EPM sample data model (SNWD_*) when creating table fields for sales
order (header) table.
● Access related business data from associated views or tables that originate in the EPM sample data model.
Since SAP NetWeaver AS for ABAP 7.52 SP00, you can create and work with database tables in ABAP
Development Tools (ADT) using the source-based editor.
1. Open the source-based ABAP Dictionary editor in ADT and create the database table ZDEMO_SOH with
the fields as they are listed below. For further information, see:
2. Edit the database table as follows:
Results
The table ZDEMO_SOH represents the active persistence for the draft sales order business object to be
generated. Each table field corresponds to an attribute of the sales order business object represented by the
entire table.
5.3.1.2 Defining the CDS Data Model for the Draft Business
Object
For didactic reasons, we will keep the data model as simple as possible. We will therefore reduce the number of
business-relavant fields to a minimum set of view fields – as listed in the table below.
SalesOrder
OverallStatus
Every BO view must include specific @ObjectModel annotations that indicate, for example, the draft
persistence or the key of the given entity. The BO view of the root entity in particular requires certain additional
view annotations in order to trigger automatic generation of a draft BO whose name corresponds to the
respective BO view.
@ObjectModel: {
transactionalProcessingEnabled: true,
createEnabled: true,
deleteEnabled: true,
updateEnabled: true,
writeActivePersistence: '<DatabaseTable/View>',
semanticKey: ['<SemanticKeyName>',... ]
}
compositionRoot: true Defines the root of the compositional hierarchy for the (draft) business
object to be created
createEnabled: true Allows you to create new business object instances in the active persis
tence
deleteEnabled: true Allows you to delete business object instances in the active persistence
updateEnabled: true Allows you to update existing business object instances in the active per
sistence
writeActivePersistence: Specifies a database table or a database view for storing active data
'<database table/view>'
@ObjectModel: {
draftEnabled: true,
writeDraftPersistence: '<DraftTable>'
}
writeDraftPersistence: Specifies the name of the database table for storing draft data
'<database_table>
This table is automatically generated by BOPF after activation of the CDS
BO view.
@ObjectModel: {
entityChangeStateId: '<ChangedAt>'
}
entityChangeStateId: Refers to a single element that contains the change state of an active instance of
'<ChangedAt>' a buisiness object.
Usually, elements like last changed timestamp, hash values, or version counters
are used for ETag check.
● The DDL-based data definition, as the corresponding development object, is already created in the ABAP
package of your choice. In our case, the data definition and the business object view are named as
ZDEMO_I_SALESORDER_TP_D and ZDEMO_I_SalesOrder_TP_D respectively.
● For further information, see: Create a Data Definition for CDS View [page 13]
● The persistence model is already defined. In particular, you have already created and activated the
database table ZDEMO_SOH that serves as the data source for the business object view.
Caution
Whenever the table field names and the corresponding element names in the business object view are
different (except for camel-case), this will cause problems when activating the view. For further
information on how to avoid such an issue, see also: Mapping CDS View-Elements onto Table Fields
[page 286]
● The key in the data model corresponds to the UUID-based primary key SALESORDERUUID of the underlying
database table.
The following listing provides you with the implementation of our simple sales order data model with the
database table ZDEMO_SOH defined as the data source for the corresponding CDS view
ZDEMO_I_SalesOrder_TP_D (camel case notation!). The same table ZDEMO_SOH also serves as a storage
location for changes to business object data that result from transactional behavior. Therefore, this table is
specified in the @ObjectModel.writeActivePersistence annotation. For the draft persistence, the draft
table ZDEMO_SOH_D is referenced in the @ObjectModel.writeDraftPersistence annotation.
To be able to access business data from other entities (business partner, overall status), corresponding
associations are defined as part of the data model. These associations refer to CDS views that are already
provided as part of the EPM data model.
This CDS view also provides an element changedat for ETag check. With the @Semantics sub-annotation
systemDateTime.lastChangedAt, the corresponding value contains the date and time of the creation or
last change that is recorded by the database.
@AbapCatalog.sqlViewName: 'ZDEMO_I_SOH_V'
@AccessControl.authorizationCheck: #NOT_REQUIRED
@Search.searchable: true
as select from zdemo_soh as SalesOrder -- the sales order table is the data
source for this view
/* Cross BO associations */
association [0..1] to SEPM_I_BusinessPartner as _BusinessPartner
on $projection.BusinessPartner = _BusinessPartner.BusinessPartner
{
-- UUID-based key is required to enable draft capabilities
@ObjectModel.readOnly: true
key SalesOrder.salesorderuuid as SalesOrderUUID,
@Search.defaultSearchElement: true
@ObjectModel.readOnly: true
SalesOrder.salesorder as SalesOrder,
@ObjectModel.foreignKey.association: '_BusinessPartner'
SalesOrder.businesspartner as BusinessPartner,
@Search.defaultSearchElement: true
@ObjectModel.foreignKey.association: '_OverallStatus'
SalesOrder.overallstatus as OverallStatus,
@Semantics.systemDateTime.lastChangedAt: true
SalesOrder.changedat as ChangedAt,
@Semantics.systemDateTime.createdAt: true
SalesOrder.createdat as CreatedAt,
@Semantics.user.createdBy: true
SalesOrder.createdby as CreatedBy,
@Semantics.user.lastChangedBy: true
SalesOrder.changedby as ChangedeBy,
/* Associations */
_BusinessPartner,
_OverallStatus
Once you have ensured that the syntax of the CDS view is complete and correct, you can activate the data
definition (as the corresponding development object).
The activation procedure generates, the following new development objects are generated in your package:
For more information about the generated business object, see Checking the Generated Business Object [page
118].
As a result of successful activation, the BOPF runtime creates a business object ZDEMO_I_SALESORDER_TP_D
(upper-case notation!) with draft capabilities that is named after, and is stored in, the same package as the
underlying CDS view, in our case: ZDEMO_I_SalesOrder_TP_D (camel case notation!). If you move the cursor
over the decorator, an info screen informs you that the business object has been generated for the CDS view. In
addition, the info screen provides you with a link to the business object editor.
On the entry page of the BO editor, you can identify the constants interface that has been generated together
with the draft business object.
Remember
A constants interface is an ABAP interface that is dedicated to a specific business object. The interface
includes constants for each business object’s entity, such as nodes, attributes, and so on. We will use it
later when we provide additional business logic using BOPF determinations, validations, or actions.
If you now choose Go to the ROOT node, you can view additional details at the entity level of the draft business
object. You must know these when you proceed to use the BOPF API - for example, when implementing a
determination. Here, you can find the names of the ABAP Dictionary objects (including the draft table) that
have been generated together with the draft business object.
Note
The transition of draft data to the permanent active data persistence is implemented using a BO-specific
draft class. For our scenario (developing a new transactional app with draft capability), the generated draft
class comes with a default implementation. As an application developer, you do not therefore need to
provide any code to comply with the draft contract.
As part of the business object generation, several ABAP Dictionary Objects are generated for each node. These
structures are used during runtime.
Persistent Structure
The persistent structure contains fields that indicate the state of the corresponding entities.
businesspartner
overallstatus
hasactiveentity If this field is flagged, the persistent structure relates to a draft which is created
based on an active entry, whose UUID can be found in the field activeuuid.
For create requests, this field indicates if the values are written to the active
database table or the draft database table.
Combined Structure
The combined structure contains structural information about the node and the persistent structure.
parent_key
root_key
Database Table
The database table is the draft table, whose name is specified in the root CDS view. The table is generated on
generation of the business object.
salesorder
businesspartner
overallstatus
hasactiveentity Indicates if the draft data records has an active version in the active database
table. .
As you already know, the BOPF framework automatically includes the basic transactional operations (CRUD).
Depending on the scenario, however, it may be necessary to provide additional application-specific business
logic. For example, the following functionality is required for our sales order-processing scenario:
The end user should already have the possibility to create new sales orders based on the generated draft
business object. To provide data consistency, we must therefore ensure that the application automatically
calculates an ID for the sales order to be created.
We will implement this requirement using a BOPF determination, which allows us to calculate a new sales order
ID at the level of the generated BO node. In a first step, we will therefore create a determination called
Preview
The end user has the option to create a new sales order and then edit the corresponding draft data. The system
then calculates the sales order ID for the new (draft) version.
As you already know, the BOPF framework automatically includes the basic transactional operations (CRUD).
Depending on the scenario, however, it may be necessary to provide additional application-specific business
logic. For example, the following functionality is required for our sales order-processing scenario:
The end user should already have the possibility to create new sales orders based on the generated draft
business object. To provide data consistency, we must therefore ensure that the application automatically
calculates an ID for the sales order to be created.
We will implement this requirement using a BOPF determination, which allows us to calculate a new sales order
ID at the level of the generated BO node. In a first step, we will therefore create a determination called
CALC_SALESORDER_ID for the sales order node, configure it appropriately for our use case, and finally, provide
the implementation for this determination.
EXECUTE Method
The execute method performs the determination at runtime.
To implement this method, add the source code from the listing below to the method /bobf/
if_frw_determination~execute.
Note
In the example source code listed below, we provide a relatively simple solution for generating a sales order
IDs. In a real application scenario, bear in mind that you might retrieve such an ID from a number range
object defined in our SAP system.
method /BOBF/IF_FRW_DETERMINATION~EXECUTE.
"Find the highest used sales order number in both active and draft data
io_read->retrieve(
EXPORTING
iv_node = is_ctx-node_key " uuid of node name
it_key = it_key " keys given to the
determination
IMPORTING
eo_message = eo_message " pass message object
et_data = lt_data " itab with node data
et_failed_key = et_failed_key " pass failures
).
"Assign numbers to each newly created line and tell BOPF about the
modification
LOOP AT lt_data REFERENCE INTO DATA(lr_data).
IF lr_data->salesorder IS INITIAL.
ADD 1 TO lv_max_salesorder.
lr_data->salesorder = lv_max_salesorder.
io_modify->update(
EXPORTING
iv_node = is_ctx-node_key " uuid of node
iv_key = lr_data->key " key of line
is_data = lr_data " ref to modified data
it_changed_fields = VALUE
#( ( ZIF_DEMO_I_SALESORDER_TP_D_C=>sc_node_attribute-zdemo_i_salesorder_tp_d-
salesorder ) )
).
ENDIF.
ENDLOOP.
endmethod.
A consumption CDS view (also referred to as consumption view) allows a business object view to be consumed
in a different manner by different OData services. Each service-specific view is defined on top of a business
object view and exposes its fields. A consumption view enhances the data model with metadata, additional
associations, or even with transient fields that fit a given consumption use case.
The @ObjectModel annotations are also used in the consumption views to enable draft capability and the
transactional-related aspects of the business data model.
Remember
According to the CDS rule, we have to double-maintain the @ObjectModel annotations that have the VIEW
scope. In the CDS views, only the annotations with the ELEMENT and ASSOCIATION scope are inherited
from the BO view.
@ObjectModel: {
transactionalProcessingDelegated: true,
createEnabled: true,
deleteEnabled: true,
updateEnabled: true
}
@ObjectModel: {
draftEnabled: true, -- on root consumption only
draftEnabled: true Allows a consumer to create draft data for a business object instance
Based on the sales order BO view, we are now going to implement the data model for consumption with the
help of the consumption view.
Prerequisites
● The DDL-based data definition, as the corresponding development object (without content), is already
created. If you have not yet already done so, follow the steps from the topic .
In our case, the DDL data definition and the CDS view are named ZDEMO_C_SALESORDER_TP_D and
ZDEMO_C_SalesOrder_TP_D respectively.
● The business object CDS view that you implemented in the previous step serves as the data source for the
consumption view.
● The UUID-based key in the data model in the consumption view corresponds to the primary key of the
underlying database table.
In this implementation, the business object view is the data source of the consumption view
ZDEMO_C_SalesOrder_TP_D. The @ObjectModel.transactionalProcessingDelegated: true
annotation indicates that transaction requests to the consumption view are delegated to the underlying
business object view. To permit the use of metadata extensions, the @Metadata.allowExtensions
annotation with the value true is added.
To expose this elementary data model composition and its metadata as an OData service, the consumption
view is annotated with @OData.publish: true (auto-exposure option).
The SELECT list includes a set of fields that are relevant for consumption in a user interface (UI).
For this scenario, the key must be specified as the (technical) UUID-based key SalesOrderUUID.
@AbapCatalog.sqlViewName: 'ZDEMO_C_SOH_V'
@AccessControl.authorizationCheck: #NOT_REQUIRED
@Search.searchable: true
@Metadata.allowExtensions: true
@ObjectModel: {
@OData.publish: true
{
-- UUID-based key required
key SalesOrder.SalesOrderUUID,
@Search.defaultSearchElement: true
SalesOrder.SalesOrder,
SalesOrder.BusinessPartner,
@Search.defaultSearchElement: true
SalesOrder.OverallStatus,
/* Exposing associations */
SalesOrder._BusinessPartner,
SalesOrder._OverallStatus
}
After successful activation of the corresponding data definition development object, ABAP Development Tools
generates several SAP Gateway artifacts that are stored in the back end of the Application Server ABAP and are
required for OData service activation in the SAP Gateway hub. These artifacts include:
● The actual service artifact with the technical name <CDS_VIEW>_CDS. Available at SAP Gateway Business
Suite Enablement - Service object (object type: R3TR IWSV).
● An SAP Gateway model (object type: R3TR IWMO) with the name <CDS_VIEW>_CDS.
● An SAP Gateway annotation model (object type R3TR IWVB) with the name <CDS_VIEW>_VAN
● An ABAP class ZCL_<CDS_VIEW> (in the case of local objects) or <Namespace>CL_<CDS_VIEW> (other
objects) that is used to provide model metadata to the SAP Gateway service.
All generated service artifacts are automatically added to the same ABAP package as the underlying
consumption CDS view.
To make your data model ready for consumption, you only have to activate the resulting OData service in the
SAP Gateway hub.
For further information, see: Generating OData Service With Auto-Exposure [page 19]
Activated OData service is listed in the Service Catalog of the SAP Gateway
Tip
To verify that the activated OData service works correctly, you can test the service. For further
information, see: Test the Activated OData Service [page 26]
Related Information
To separate the metadata specified in the annotations from the actual data definition in the view, the
consumption views are not used to enhance the data model with UI-specific annotations for later consumption
@Metadata.layer: #CORE|CUSTOMER|INDUSTRY|LOCALIZATION|PARTNER
@UI: {
...
}
annotate view <CDS_View> with
{
@UI: {
...
}
<element_name>;
...
}
Note
Before the annotate view statement, the @Metadata.layer annotation must be specified with an
enumeration value in order to define the layer for the metadata extension. This layer determines the
priority of the metadata if multiple metadata extensions exist for the same CDS view.
Prerequisites
CDS (consumption) views are not extensible by default. To use a metadata extension for a view, you must
consider the following condition:
The @Metadata.allowExtensions annotation must be added with the value true in the definition of the CDS
(consumption) view. This annotation explicitly permits the use of metadata extensions.
Context
Metadata extensions enable you to write UI annotations for a CDS (consumption) view in a different
development object in order to separate them from the CDS view. A metadata extension is a transportable
ABAP development object.
Procedure
1. In your ABAP project, select the relevant package node in the Project Explorer.
2. Open the context menu and choose New Other ABAP Repository Object Core Data Services
Metadata Extension to launch the creation wizard.
3. Enter the name ZDemo_E_SalesOrder_TP_D and the description for the metadata extension to be
created.
4. Choose Next.
5. Assign a transport request.
6. Choose Finish.
Results
In the package selected, the ABAP back-end system creates an inactive version of a metadata extension. You
can now start to define metadata extensions.
@Metadata.layer: #CUSTOMER
@UI: {
headerInfo: {
typeName: 'Sales Order',
typeNamePlural: 'Sales Orders',
title: { type: #STANDARD, value: 'SalesOrder' }
}
}
@UI: {
lineItem: [ { position: 10, label: 'Sales Order ID', importance: #HIGH } ],
selectionField: [ { position: 10 } ],
identification:[ { position: 10, label: 'Sales Order ID' } ]
}
SalesOrder;
@UI: {
lineItem: [ { position: 20,label: 'Customer', importance: #MEDIUM } ],
identification: [{ position: 20, label: 'Customer' }]
}
BusinessPartner;
@UI: {
lineItem: [ { position: 30, label: 'Status', importance: #MEDIUM } ],
identification:[ { position: 30, label: 'Status' } ],
selectionField: [ { position: 30} ]
}
OverallStatus;
}
In the listing above, the value CUSTOMER is used for the metadata extension layer. This is the highest level. If
several metadata extensions are provided for a data definition, the system considers the metadata extension
with the highest value.
To make sure that all parts of the application work correctly for the end user, we are now going to run the
resulting application.
Prerequisites
● The consumption view ZDEMO_C_SalesOrder_TP_D is exposed as an OData service using the auto-
exposure approach (@OData.publish: true).
For further information, see: Generating OData Service With Auto-Exposure [page 19]
● The resulting OData service has been activated in the SAP Gateway hub.
For further information, see: Activate OData Service in the SAP Gateway Hub [page 22]
● Fiori elements are used as building blocks during UI development.
For further information, see: Consume Business Data Using SAP Fiori Elements [page 27]
Procedure
If you run the new app based on Fiori elements in the Fiori Launchpad, the resulting UI provides you with a list of
sales orders, including all fields that you exposed for consumption. In our case however, the initial screen with
the list of sales orders is still empty.
To create a new sales order instance, choose the + icon and maintain all the fields required to specify the sales
order header.
Remember
Each field that results from an association’s path provides you with predefined value help options. For
further information, see:
If the changes to the sales order header fields have not been saved, a draft version of the sales order instance is
created.
Draft version of the new sales order instance in the list report (after navigating back from the object page)
For the given sales order instance, the draft data is transferred to the active data only upon saving.
Up to now, we have used a greatly simplified data model for our example scenario. In this chapter, however, we
will set out a realistic scenario and use a two-level data model by adding sales order items. As a result, the sales
order item will be added as a subnode of the sales order draft business object.
The figure below shows the extended data model with the compositional hierarchy of the sales order header,
the business partner, the sales order item, and the product. In this case, the sales order header represents the
composition root of the data model.
Remember
In draft scenarios, there might be two versions of target data for an association: active data and draft data.
To ensure that the association not only reaches active data, it must be draft-enabled. Draft-enabled
associations retrieve active data if you follow the association from an active instance and it retrieves draft
data if you follow it from a draft instance.
As the association to Sales Order Item represents a composition of the business object, the association in
the case under consideration is draft-enabled by default.
There are other cases, for example cross-BO associations, for which draft-enablement needs to be
implemented manually.
For more information about associations in the draft context and how to draft-enable them, see:
Implementing Draft-Enabled Associations [page 288].
Modelling the Normalized Data Persistence for the Sales Order Item
Open the source-based ABAP Dictionary editor in ADT and create the database table ZDEMO_SOI with the
fields listed below.
SALESORDERITEM SNWD_SO_ITEM_POS
PRODUCT SNWD_PRODUCT_ID
GROSSAMOUNT SNWD_TTL_GROSS_AMOUNT
CURRENCYCODE SNWD_CURR_CODE
QUANTITY INT4
Caution
For performance reasons, we recommend defining the root UUID field (in our case, the salesorderuuid
field) as a key field in the sales order items table.
Create the data definition ZDEMO_I_SALESORDERITEM_TP_D and define a business object CDS view that
exposes the fields listed below.
Related Topic: Defining the CDS Data Model for the Draft Business Object [page 113]
SalesOrderUUID
SalesOrderItem
GrossAmount
CurrencyCode
Qunatity
Product Product
As you can see in the listing below, a set of associations is defined as part of the data model for a sales order
item. Compositional associations define the view compositional hierarchy by providing an association to the
different (root/parent) entities along the given composition path.
@AbapCatalog.sqlViewName: 'ZDEMO_I_SOI_V'
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Sales Order Items - subnode BO view'
@Search.searchable: true
@ObjectModel: {
semanticKey: [ 'SalesOrderItem' ],
writeActivePersistence: 'ZDEMO_SOI',
createEnabled: true,
deleteEnabled: true,
updateEnabled: true,
writeDraftPersistence: 'ZDEMO_SOID' -- Draft persistence
}
define view ZDEMO_I_SalesOrderItem_TP_D
as select from zdemo_soi as SalesOrderItem
/* Compositional associations */
association [1..1] to ZDEMO_I_SalesOrder_TP_D as _SalesOrder on
$projection.SalesOrderUUID = _SalesOrder.SalesOrderUUID
/* Cross BO associations */
association [0..1] to SEPM_I_Product_E as _Product on
$projection.Product = _Product.Product
/* Associations for value help */
association [0..1] to SEPM_I_Currency as _Currency on
$projection.CurrencyCode = _Currency.Currency
Remember
CDS views that do not represent the root node of the hierarchy must have an association to their
compositional parent view annotated with #TO_COMPOSITION_PARENT. In addition, they must have a
#TO_COMPOSITION_ROOT association for performance reasons. However, the difference between the two
association types is effective only from the third level of data model hierarchy.
In the root BO view ZDEMO_I_SalesOrder_TP_D, add the compositional association _Item that corresponds
to the listing below. The specified association must also be annotated appropriately in the projection by using
the @ObjectModel.association.type annotation with the appropriate value: #TO_COMPOSITION_CHILD.
This annotation defines which associated BO views are to be created as subnodes of the draft BO.
...
...
/* Compositional associations */
/* Exposed associations */
@ObjectModel.association.type: [#TO_COMPOSITION_CHILD]
In this activation step, both the draft persistence and the draft BO are (re)generated based on the new data
model.
Tip
The previously inactive data definition for the SO item view (ZDEMO_I_SalesOrderItem_TP_D) is
referenced in the SO root view (ZDEMO_I_SalesOrder_TP_D). This causes the corresponding code line to
issue an error in the root view. However, this error can be fixed by activating both objects in a single step.
Procedure
1. In the Project Explorer tree of your ABAP project, use multiple selection to select both relevant data
definitions ZDEMO_I_SALESORDER_TP_D and ZDEMO_I_SALESORDERITEM_TP_D.
2. Choose Activate from the context menu or the toolbar.
Results
As a result of this activation procedure, the extended draft BO is generated.
In this topic, we want to extend the metadata model of the generated draft BO to provide additional application
logic. Now, the end user should be able to add new items to a sales order header.
Preview
If the end user clicks on the Fiori UI in the edit mode, he or she has option to create a new item (as a draft) and
then edit the corresponding draft data. The user should also be able to select and then delete individual items.
Not all fields of the sales order draft item are initially populated with data. In our case, only the product and the
quantity fields are to be specified by the user.
When the user chooses the Add button, the data for the new item is generated as a draft version.
The position of the new item is calculated using the existing item positions, whereas the amount data are
determined on the basis of the table records.
For the given sales order instance, the draft data of the new item is transferred to the active data only upon
saving.
Development Steps
To implement the missing calculations for the item position and the total amount of an item, you must first
create corresponding determinations (GET_ITEM_POSITION and CALC_AMOUNT) at the level of the sales order
item subnode, configure them by means of appropriate trigger conditions and finally implement the
determination class.
Related Topic: Providing Additional Business Logic with a BOPF Determination [page 121]
Listing: EXECUTE method of the determination implements the calculation of item positions
Related Topic: Providing Additional Business Logic with a BOPF Determination [page 121]
Listing: EXECUTE method of the determination is used to retrieve and calculate the total
amount for an item
Based on the BO view for the sales order items, we are now going to implement the data model for
consumption with the help of the CDS consumption view.
Create a DDL-based data definition with the name ZDEMO_C_SALESORDERITEM_TP_D as the required
development object and define the CDS view ZDEMO_C_SalesOrder_TP_D in accordance with the listing
below.
@AbapCatalog.sqlViewName: 'ZDEMO_C_SOI_V'
@AccessControl.authorizationCheck: #NOT_REQUIRED
@Metadata.allowExtensions: true
@Search.searchable: true
@ObjectModel: {
semanticKey:['SalesOrderItem'],
createEnabled: true,
deleteEnabled: true,
updateEnabled: true
}
{
@ObjectModel.readOnly: true
key SalesOrderItem.SalesOrderItemUUID,
@ObjectModel.readOnly: true
SalesOrderItem.SalesOrderUUID,
@Search.defaultSearchElement: true
_SalesOrder.SalesOrder,
SalesOrderItem.SalesOrderItem,
SalesOrderItem.Product,
SalesOrderItem.GrossAmount,
SalesOrderItem.Quantity,
/* Exposed associations */
@ObjectModel.association.type: [ #TO_COMPOSITION_ROOT,
#TO_COMPOSITION_PARENT ]
_SalesOrder,
_Product,
_Currency
}
Related Topic: Providing a Consumption View for the Sales Order [page 125]
...
define view ZDEMO_C_SalesOrder_TP_D
...
/* Composition and cross BO associations */
association [0..*] to ZDEMO_C_SalesOrderItem_TP_D as _Item on
_Item.SalesOrderUUID = SalesOrder.SalesOrderUUID
...
{
...
/* Exposing value via associations */
@ObjectModel.association.type: [ #TO_COMPOSITION_CHILD ]
_Item,
...
}
Procedure
1. In the Project Explorer tree of your ABAP project, use multiple selection to select both relevant data
definitions ZDEMO_C_SALESORDER_TP_D and ZDEMO_C_SALESORDERITEM_TP_D.
2. Choose Activate from the context menu or the toolbar.
In this step, we make use of a metadata extension to annotate UI metadata of the consumption view for the
sales order item.
Prerequisites
CDS (consumption) views are not extensible by default. To use a metadata extension for a (comnsumption)
view, you must consider the following condition:
The @Metadata.allowExtensions annotation must be added with the value true in the definition of the CDS
(consumption) view. This annotation explicitly permits the use of metadata extensions.
Create a metadata extension with the name ZDEMO_E_SALESORDERITEM_TP_D as the required transportable
ABAP development object and add the UI metadata from the listing below.
Adding UI Metadata
@Metadata.layer: #CUSTOMER
@UI: {
headerInfo: {
typeName: 'Sales Order Item',
@UI.hidden: true
SalesOrderUUID;
@UI.hidden: true
SalesOrder;
@UI: {
lineItem: [ { position: 10, label: 'Position', importance: #HIGH } ],
identification:[ { position: 10, label: 'Position' } ]
}
SalesOrderItem;
@UI: {
lineItem: [ { position: 20, label: 'Product', importance: #MEDIUM } ],
identification:[ { position: 20, label: 'Product' } ]
}
Product;
@UI: {
lineItem: [ { position: 30, importance: #MEDIUM, label: 'Quantity' } ],
identification:[ { position: 30, label: 'Quantity' } ]
}
Quantity;
@UI.hidden: true
CurrencyCode;
@UI: {
lineItem: [ { position: 40, importance: #MEDIUM } ],
identification:[ { position: 40 } ]
}
GrossAmount;
}
To make the UI metadata effective for the OData service at runtime, you must activate the corresponding
development object (metadata extension ZDEMO_E_SALESORDERITEM_TP_D).
To make sure that the extended parts of the application also work correctly for the end user, we are now going
to run the resulting app based on Fiori elements as building blocks.
For this purpose, we must create a new List Report Application project in the Web IDE.
Defining the navigation path from SO header to SO item when creating a WEB IDE project
In this topic, we extend the current implementation of our sample scenario to include a consistency validation
for the draft data when editing sales order items. This consistency validation checks specifically if the quantity
data of a product is valid. If it is not, the consistency validation prevents the draft data from being saved as
active data version. This ensures that only consistent sales order item instances can be saved.
Preview
If the end user clicks on the Fiori UI in edit mode, he or she has the option to create a new item (as a draft) and
then edit the corresponding draft data. The value entered in the quantity field must be checked for validity.
After the end user presses the ENTER key or clicks into another input field, the system recognizes negative
values as faulty and marks the quantity field accordingly in the Fiori UI. In addition, a corresponding error
message is displayed to the end user.
We will create a BOPF validation at the level of the sales order item subnode, configure it by means of an
appropriate trigger condition and then implement the consistency validation interface to check whether the
entered quantity values are positive.
Remember
In BOPF, a validation is an entity of a business object node that is triggered in certain situations to check
various aspects of a given set of node instances. In particular, consistency validations check if a node
instance is consistent under consideration of the consistency criteria imposed by the business
requirements. Such validations are called at pre-defined points within the BOPF BO transaction cycle to
ensure that BO nodes are persisted in a consistent state. These points can be configured for consistency
validations. Each such validation configuration contains a trigger condition that is checked by BOPF at
several time points during the transaction. If the trigger condition is fulfilled, the consistency validation is
executed. Otherwise, if there are inconsistent node instances, a consistency validation sends messages to
the consumer and prevents the transaction from being saved until the inconsistency is corrected.
Creating and Configuring the Validation for the Sales Order Item Subnode
Procedure
1. To create a BOPF validation for the sales order item subnode, open the BO editor with the associated item
node (in our case: ZDEMO_I_SALESORDERITEM_TP_D) and choose the Validations tab.
2. Choose New... to launch the New Validation wizard.
3. Specify the details:
○ Name: POSITIVE_QUANTITY_VAL
○ Description: Enter a short description that describes the purpose of the validation.
Results
The BOPF framework assigns the new validation to the business object subnode for sales order items and
creates a validation class that implements the BOPF validation interface /BOBF/IF_FRW_VALIDATION.
To implement this method, add the source code from the listing below to the method/bobf/
if_frw_validation~execute. This method implements the main validation logic. It does not provide any
modifying access to the node’s instance data but returns the messages and the keys of failed node instances
(instances for which the save action may not be executed). For each sales order item (remember that we make
use of “mass-enabled” implementation), we check if the value <s_sales_order_item>-quantity is
negative.
METHOD /BOBF/IF_FRW_VALIDATION~EXECUTE.
IF <s_sales_order_item>-isactiveentity = abap_false.
ENDIF.
ENDLOOP.
ENDMETHOD.
You may wish to extend the current scenario to include a further step. For example, you may be interested in
extending the business logic so that status changes to individual instances of the sales order can be executed
without the end user having to switch to edit mode. In this case, the BOPF actions come in to play.
We have already demonstrated the corresponding development steps in another context. (For further
information, see: Extending Apps with Quick Actions [page 96] )
Note
The general steps listed below remain valid also in the draft context and can easily be applied to our
example scenario. Be aware that the example code must be modified at some points there to match the
data model of this scenario.
Tip
If you have arrived at this point, you might consider extending the present example scenario to include
some further interesting features of the programming model. For example, you could enable or disbale the
action SET_TO_PAID depending on the status of the sales order. To provide such dynamic action control to
the data model, you must implement the property determination class of the Sales Order BO.
For more detailed information on how you can provide such dynamic control, refer to topic: Dynamic Action
Control [page 201]
Overview Graphic
This figure illustrates the different authorization checks for your apps
Development Tasks
Administrative Tasks
Business applications require an authorization concept for their data and for the operations on their data.
Display and CRUD operations, as well as specific business-related activities, are therefore allowed for
authorized users only.
In a transactional development scenario, you can add authorization checks to various components of an
application. In this case, different mechanisms are used to implement the authorization concept.
ABAP CDS has its own authorization concept based on a data control language (DCL). The authorization and
role concept of ABAP CDS uses conditions defined in CDS access control objects to check the authorizations
of users for read access to the data model and data in question. In other words, access control allows you to
limit the results returned by a CDS entity to those results you authorize a user to see.
More on this: Implementing Authorizations for Read-Only Applications [page 156] and
In BOPF, an authorization check is introduced as an entity of a business object node used to manage
authorizations on the node level. Using this authorization and role concept allows you to check whether a user
is allowed to perform a certain activity (action) at the node instances or to manipulate certain node data
(create, delete, and update operations).
More on this: Implementing Authorizations for Generated Business Objects [page 160]
SAP Gateway provides predefined roles as templates for developers, administrators, end users of the content
scenarios, and support colleagues. You, as the SAP customer, will configure the roles based on these templates
and assign users to the roles.
More on this: Defining Authorizations for External Service Consumption [page 168]
The figure below provides you with an overview of the main design time components in a transactional
development scenario, including the artifacts required for enabling authorization checks at all levels of the
application.
Normalized views (or database tables) serve as the data source for modeling the data associated with the
business object layer. To check the authorizations of users for read access to CDS-based data model and data,
a corresponding CDS role is defined using the data control language (DCL). A CDS role specifies access rules.
Each access rule defines access to the CDS view that the role is assigned to. Different access controls are
created for access control at business object data model level (in figure: Business Object CDS View) and at the
consumption level (in figure: Consumption CDS View).
The root BO CDS view is also used to generate the corresponding BOPF BO. The generated BO provides
appropriate code exits for implementing the CRUD authorization contract based on well-defined authorization
BOPF APIs.
For developers at SAP, no further steps (concerning authorizations) are required for the resulting OData service
to be consumed in the customer’s landscape. SAP gateway already provides predefined roles as templates for
accessing the OData services and SAP Fiori apps.
Development Process
Access controls with DCLs enables you to add an authorization filter directly to a query of a CDS entity. The
filter then limits the data the user can see.
We have created the SalesOrderItem CDS entity (see Define a Data Model Based on CDS Views [page 13]
above). Now we want to add user authorizations to restrict the query results. Here we describe use cases with
exampes of access controls for this CDS entity.
Access controls enable you to filter access to data in the database based on fixed values or conditions on
PFCG, among others. We use data control language (DCL) to write access controls. If no access control is
created and deployed for the CDS entity, a user who can access the CDS entity can view all the data returned.
For more information about how to start the access control editor, see .
In this example, we restrict access to the items with currency code EUR. This example is a very simple one,
because you could achieve the same thing much easier by adding a WHERE condition to the CDS entity like
WHERE CurrencyCode = EUR. In the next example we will add user relevant values.
Code Syntax
Data Preview of Sales Order Item with Access Limited to Currency Code Euro
If you use the PFCG_AUTH aspect in the access control, user-dependent PFCG authorizations are used when
accessing the CDS view. To implement this, there must be a PFCG object in the ABAP system. If you want to
see the data, your user must be assigned a role that includes this authorization object with the matching value
in the relevant field.
In this example, we have the same CDS entity SalesOrderItem again, and we want to limit the results by the
value of the authorization object S_ACM_DEMO, which we map to fields of a sales order item entity.
Step 1: In your ABAP system, use transaction SU01 to assign your user the role that includes the relevant
authorization object and field (in our example, the role SAP_INTNW_EPM_DEMO with the authorization object
S_ACM_DEMO).
Step 2:In the access control editor, map the field SACMTSOID of S_ACM_DEMO to the field SalesOrderID of the
CDS entity SalesOrderItem and add display authorizations (ACTVT = 03).
The code snippet below shows how you would specify this in the access control editor:
Code Syntax
In the data preview, you can see that only the items with SalesOrderIDs from 50...01 to 50...03 are displayed.
Use Case 3: Access Control with Combination of Fixed Value and PFCG
Authorization
You can use the AND and OR operators to join conditions. In this example, we combine use cases 1 and 2 to
only retrieve sales order items with SalesOrderIDs from 50...1 to 50...3 and currency code Euro:
Code Syntax
In the data preview, you can see that only the items with SalesOrderID from 50...01 to 50...03 and currency
code Euro are displayed.
If you are going to implement application-specific authorizations, you must consider the state of the business
entity (active or draft data version).
Remember
● Active data represents the state of the business entity that is stored in the active persistence.
● Draft data represents the transient state of a business entity until it is permanently stored in the
persistence layer as active data. The draft data is stored in the draft persistence pending transition to
the active data.
The authorization checks for active data require an application-specific authorization exit class to be
implemented at root node level of the business object.
To create an authorization exit class for the relevant BO, open the editor for the root node and choose the
Authorization tab. Here, you can check first whether an authorization class is already assigned to the relevant
BO root node. If this is not the case, you can create a new one or assign an existing one as the authorization
class.
PUBLIC SECTION.
METHODS:
/bobf/if_lib_auth_draft_active~check_static_authority REDEFINITION,
/bobf/if_lib_auth_draft_active~check_instance_authority REDEFINITION.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
METHOD /bobf/if_lib_auth_draft_active~check_static_authority.
ENDMETHOD.
METHOD /bobf/if_lib_auth_draft_active~check_instance_authority.
ENDMETHOD.
ENDCLASS.
In the implementation of this method, you can check whether the user has the permission to access a
functionality at all. The result of this static check does not depend on the specific node instance (data value).
Note
This is usually called before execution of a core service in order to check whether the user has
authorization to execute the functionality at all.
Note
This method is usually called once the static authorization check has been passed.
In case of executing an action that is assigned to a subnode, for example, or when modifying a subnode (CRUD
operations), the DISPLAY authorization (activity: DISPLAY) and the CHANGE authorization (activity: CHANGE)
are requested from the root node where the authorizations are calculated in the corresponding authorization
exit class.
Unlike active BO instances, an authorization check is explicitly required for draft versions of BO instances only
in rare situations. This is because the creator of draft is always allowed to perform delete and update
operations as well as execute actions. In those cases, the authorization exit is not invoked. However, while
creating or activating the draft version, the following use cases should be considered:
In the source code of this method check if the creation of a new draft instance is granted for the respective
users:
method /bobf/if_lib_auth_draft_active~check_static_authority.
...
case is_ctx-activity.
when /bobf/cl_frw_authority_check=>sc_activity-create.
" Check the static CREATE authorization here...
...
endmethod.
If you need an instance-based check in very specific cases, you can wrap the creation of the instance into
an action and implement the instance-based authorization check there too. Creating of a new draft version
of a BO instance without a relationship with an active version makes it necessary to check for CREATE on
the active node instance.
Note that the instance-based part of authorization check is not implemented in the authorization exit class but
in the draft class to be executed immediately before copying the active data to the draft instance.
For implementing a static check the authorization exit class is used. In this case, the check is calculated in the
check_static_authority method with activity = EXECUTE and action_name = EDIT.
method /bobf/if_lib_auth_draft_active~check_static_authority.
...
case is_ctx-activity.
when /bobf/cl_frw_authority_check=>sc_activity-create.
" Check the static authorization here...
...
endmethod.
method /bobf/if_frw_draft~create_draft_for_active_entity.
...
Note that the authorization check is not implemented in the authorization exit class but in the draft class to be
executed at runtime immediately before copying the draft data to the active instance.
method /bobf/if_frw_draft~copy_draft_to_active_entity.
...
" Check both, the static and instance-based UPDATE authorization here
...
endmethod.
Business applications require an authorization concept for their data and for operations on their data. Display,
create, delete and update activities are therefore allowed for authorized users only.
Remember
In BOPF, an authorization check is introduced as an entity of a business object root node that is used for
managing authorizations. Using this authorization and role concept allows you to check whether a user can
perform a certain activity on the node instances or manipulate certain node data.
Examples
Let us assume in a sales order application that sales orders with customer_region AMERICAS must be visible
solely for authorized users. In addition, only authorized users should be able to change the status of individual
sales orders to DELIVERED by executing the SET_TO_DELIVERED action.
Remember
Note that authorization checks implemented for the BO layer are not suitable to limit read access when
using OData services. To limit read access for this uses case, add the DCL-based access control to CDS
views (BO CDS views and consumption CDS views). More on this:
The generic authorization concept in BOPF differentiates between static and instance-based authorization
checks:
● Static checks: Check whether the user has permission to perform a specific activity or an operation on
data (for example: CREATE). The result of a static check does not depend on specific data values.
● Instance-based checks: Evaluate the node data and check whether the user has permission to display or
change data, or perform a specific activity where an authorization-relevant attribute has a specific value.
The result of this check depends on the node data.
The first sales order example where customer_region AMERICAS must be visible solely for authorized
persons is therefore handled by an instance-based check, whereas the second example (sales orders can be
changed to status DELIVERED solely by authorized persons) is handled by a static check.
BOPF services always run in privileged mode. Privileged mode is the processing mode that allows the
implementation of a business object to have direct access to further resources and entities during a round trip.
This means, authorization checks are executed when a BOPF service is accessed. If the implementation of the
business object accesses further services during the roundtrip, for example, when executing a determination
or an action, or even when accessing data of other business object, then the authorization is not checked any
more.
Related Information
In the backend system, you add start authorizations for the OData services.
Prerequisites
● You have a user in the back-end system with the authorizations required for Maintain Authorization Default
Values (transaction SU24).
● You have generated the required service artifacts.
For more information, see Generate Service Artifacts From a CDS View [page 21].
Procedure
1. Open the SAP GUI for the relevant ABAP project by starting the SAP GUI Launcher ABAP Development
Tools (icon in the toolbar). Within the embedded SAP GUI, you are able to access the complete
functionality of the classic ABAP Workbench.
Note
Alternatively, you log in to the corresponding development system using the SAP GUI mode.
Use the * (asterisk) at the end of the name and then select the correct name with version (in our case:
0001).
7. Choose Object Object Add Authorization Object and enter S_SERVICE as the authorization object.
9. Add the authorization objects used in the DCL of the CDS view with Proposal Yes and specify values which
should be fixed or with Proposal Yes, Without Values
10. Save and transport your changes.
Remember
For you as service developers (at SAP), there are no further steps required for the service to be consumed
externally within the customer’s landscape. In particular, you don’t need to provide any authorization
default values of the authorization objects and specific role templates required for execution of your
service. SAP Gateway already provides predefined roles as templates for accessing SAP Fiori apps.
Using the profile generator (transaction PFCG), the authorization administrators on the customer’s side create
or extend roles based on the delivered SAP role templates.
The role templates specify the authorizations for content that can be accessed by users of the specific SAP
Fiori app within the customer’s namespace.
Related Information
You need to assign the start authorization to users. You can do that by extending the authorizations of an
existing backend role.
Prerequisites
● You have a user in the back-end system with the authorizations required for Role Maintenance (transaction
PFCG).
● Either the role already exists in the back-end system or you must create a new role and assign it to your
test user. In this procedure, we assume that you already have a role assigned to your test user.
Procedure
1. Open the SAP GUI for the relevant ABAP project by starting the SAP GUI Launcher ABAP Development
Tools (icon in the toolbar). Within the embedded SAP GUI, you are able to access the complete
functionality of the classic ABAP Workbench.
Note
Alternatively, you log in to the corresponding development system using the SAP GUI mode.
2. In the command field, enter the transaction code PFCG to start the Role Maintenance.
3. Enter the name of the backend role to be extended (in our case: ROLE-APW-68).
Use the * (asterisk) at the end of the name and then select the correct name with version (in our case:
0001) from the value help (press F4).
9. Choose Copy.
10. On the Change Roles screen, choose Save.
Now the start authorization and the authorization defaults for the service are merged into the role’s
authorizations.
Context
There are various approaches to extend an application with additional features. You can extend your application
with additional fields (either as a key user in the app or by extending the delivered code in the back end), with
additional nodes or functionality for your business object, or with an additional artifact to separate annotations
from your CDS data model.
Click the boxes to get more information about the different extensibility options.
Click the element for more information about each extensibility option.
Field Extensibility
Field extensibility means that you would like to provide additional fields in a given business application context
that is represented by the UI actually used. These are fields that were not foreseen by the application when
delivered by SAP. In such a case, you have the option to use the extensibility infrastructure of the ABAP
platform in order to add custom fields to the original application.
● Key user extensibility – You are solely interested in configurable extensions as they are used in the context
of business power user (key user) adaption.
● Custom code extensibility – You want to maximize leverage of this infrastructure for field extensibility with
custom code by implementing your own extensions.
Recommendation
If an SAP application is enabled for extensibility we recommend that you use the key user tool to create
custom fields, even as a developer, because the key user tool hides the technical details of the SAP
application from you.
On the other side, we recommend to create custom fields directly using extend view only if...
Be aware that custom code extensibility requires the entire development cycle to implement extensions by
means of code additions. This, in turn, requires an extension for the data model that was originally
delivered in the form of CDS views and was published as an OData service for further consumption.
Note
The BOPF enhancement concept is not applicable for business objects that are generated from CDS and
used within the ABAP Programming Model.
As an SAP customer you may want - in some cases - to extend the user interfaces (UI) of the On-Premise
applications delivered by SAP or SAP partners with additional fields.
Using a concrete example, this documentation section demonstrates how you, as an SAP customer, can
implement field extensions with your own custom code in the context of the ABAP CDS extension model. In
this example, we assume that the fields you want to use for your extension are already persisted on the
database.
Note
If you want to extend an application with fields that are not persisted on the database, you need to define
an append structure first. You define all the fields to be extended in this structure. This is only possible if the
database table is enabled for extensibility (annotation @AbapCatalog.enhancementCategory :
#EXTENSIBLE_ANY ).
Field Extensibility
The extensibility infrastructure of the ABAP platform enables the extension of existing application with your
own custom code. That means, when you want to include new fields into your application you do not need to
modify delivered code, but you simply attach new code to the relevant development artifacts. The
infrastructure ensures that the new elements are added to all involved layer from database to UI (ABAP
Dictionary, CDS; SAP Gateway, UI).
For each CDS view to be extended, the developer needs to create a data definition as development object and
implement the corresponding CDS view extension using EXTEND VIEW syntax:
AbapCatalog.sqlViewAppendName: 'CDS_APPEND_VIEW'
[@extension_annot1]
[@extension_annot2]
...
EXTEND VIEW cds_view_original WITH cds_view_extension
[association1 association2 ...]
{ select_list_extension } [;]
Using the syntax above, you can extend a delivered CDS view cds_view_original using a CDS view
extension cds_view_extension. The CDS view extension adds the following elements to the SELECT list of
the available view without making modifications:
● The elements of the specified extension list select_list_extension, as known from view fields
● Optional associations association1, association2, ... for the SELECT statement of the extended CDS
view
● Further annotations extension_annot1, extension_annot2... can also be specified.
Note
The CDS extension is based on the proven append technique that you probably already know from the ABAP
Dictionary. Special views, known as append views, are the type of views that you as an SAP customer can use
to add new fields to existing database views. They are intended for enhancements of database views of the SAP
standard.
Remember
With an append view, fields of the original tables can be included in the view without modifications. An
append view is assigned to one database view. However, you can create more than one append view for a
database view. For each active database view, the system looks for all the append views that are assigned
and their fields are then appended to the database view. When you create or change an append view, the
assigned database view is automatically adjusted to this change when you activate the append view.
Related Information
Prerequisites
● You need the standard developer authorization profile to create ABAP development objects with ABAP
Development Tools.
● You identified the data definition that implements the original CDS-based data model you are going to
extend.
Context
Starting Point
Let us assume you - as an SAP customer – are accessing our own Fiori Launchpad where you open a list
reporting app displaying all parties that are relevant for your business activities.
However, in your business context you may require some further details that were not foreseen by the
application’s UI delivered by SAP. For example, you would like to display the role (supplier, customer, partner,
and so on) or the contact details for each organization displayed in the list. In other words: You would like to
provide additional fields in the given business application context that is represented by the UI actually used.
Let us also assume you have identified the development object (data definition) that implements the original
data model for Party Address Data - as shown in the listing below.
@AbapCatalog.sqlViewName: 'SQL_PARTY_ORIG'
@AbapCatalog.compiler.compareFilter: true
@Search.searchable: true
@OData.publish: true
@Search.defaultSearchElement: true
@UI.lineItem: { importance: #HIGH, label: 'Organization', position: 20 }
Organization.PartyName as OrgName,
@UI.selectionField.position: 10
@Search.defaultSearchElement: true
@Search.fuzzinessThreshold: 0.5
The original source code defines quite a simple data model based on the CDS view called DEMO_PARTY_ORIG.
This view is implemented by means of a query for performing a SELECT statement, where the predefined CDS
view (that originates from the EPM demo application) SEPM_I_Party_E is used as the data source. The select
list includes a rather small set of fields for the ID, name, and location of the parties. In addition to the original
CDS view, the SQL view (database view) SQL_PARTY_ORIG has also been created in the ABAP Dictionary.
Procedure
3. Open the context menu and choose New Other ABAP Repository Object Core Data Services Data
Definition to launch the creation wizard.
4. In addition to the Project and Package, enter the Name (with due regard to your namespace) and the
Description for the extension to be implemented. Choose Next.
5. Assign a transport request and choose Next.
6. Select the Extend View template to speed up the extension definition.
Results
In the selected package, the ABAP back-end system creates an inactive version of a data definition for the
extension and stores it in the ABAP Repository. The generated source code is automatically displayed in the
DDL editor and already provides you with the necessary view annotations and adds placeholders for names of
the append view, the original CDS view, and for the actual view extension.
Next Steps
If you have not yet already done so, open the newly created data definition and specify the names of the...
This topic demonstrates how you can extend the syntax of the original CDS view with a view extension to
provide some additional custom fields.
In our example, by far not all fields from the original data source have been adopted into the data model. For
example, details on the exact address of the organizations are missing. As a substitute for further address data,
we will adopt the field CountryName into the list of line items:
...
-- Adding predefined field
@UI.lineItem: { label: 'Country', position: 35 }
Organization.CountryName
...
Fields that were not foreseen and result only after a calculation based on other defined fields are a very good
example of the use of view extensions. In the following listing, a new field named party_role has been
introduced. The values of this field are determined first within the case statement. In this way, the specification
of the role Customer or Supplier can be output for each individual organization.
...
-- Adding calculated field
@UI.lineItem: { label: 'Role', position: 25}
case Organization.PartyRole
when '01' then 'Customer'
when '02' then 'Supplier'
else 'Unspecified '
end as party_role
...
Results
The resulting source code for the CDS view extension is the following:
@AbapCatalog.sqlViewAppendName: 'ZSQL_PARTY_EXT'
@EndUserText.label: 'Party Adress Data Extended'
After successful activation of the data definition, two ABAP Dictionary objects are created for the CDS view
extension and are automatically added to the same ABAP package (and therefore the same transport request)
as the underlying DDL source:
● The actual CDS view extension that is specified after the EXTEND VIEW keyword
● The CDS append view for a classic append view that is specified in quotation marks after the
@AbapCatalog.sqlViewAppendName annotation. The new append view extends the CDS SQL database
view of the extended CDS view.
Caution
The name given to the append view can no longer be changed after the CDS view has been transported
into a follow-on system.
This topic demonstrates how you can extend the syntax of the CDS view with view extension to provide some
additional custom fields that result from new associations defined in the extension code.
Create a data definition second as the second development object for extending the original CDS view
DEMO_PARTY_ORIG and specify the names of the append view as ZSQL_PARTY_EXT2 and
ZDEMO_PARTY_EXT2 for the new view extension. This association _PartyContact associates the original CDS
view with the target data source SEPM_I_ContactPerson_E. The target is a predefined CDS view that
originates from the EPM demo application you can use to provide contact data for the business partner. For
representation of this contact data, we adopt only the field EmailAddress into the list of LineItems.
@AbapCatalog.sqlViewAppendName: 'ZSQL_PARTY_EXT2'
@EndUserText.label: 'Party Address Data Extended with Contact'
extend view DEMO_PARTY_ORIG with ZDEMO_PARTY_EXT2
association [1..1] to SEPM_I_ContactPerson_E as _PartyContact
on Organization.businesspartner = _PartyContact.businesspartner
{
@UI.lineItem: { label: 'Contact - Email', position: 50 }
Results
If you open the DDL editor with the original data definition, you will detect that (after a refresh) a new decorator
indicates that extensions are available in the current system. If you move the cursor over the decorator, an
info screen provides you with links to all existing view extensions. Prerequisites: both extension data definitions
has been activated successfully in ABAP Development Tools.
If you now open the original database view in the ABAP Dictionary (in our example: SQL_PARTY_ORIG), you will
see that all appends are included in the database view
Tip
To verify the result set of the extended CDS view, you can utilize the Data Preview. More on this: Verify the
Result Set in the Data Preview Tool [page 18]
To make sure that the added custom fields work correctly for the end user, we are now going to run the
resulting application.
Prerequisites
● The original CDS view is exposed as OData service using the so-called auto exposure approach
(@OData.publish: true).
More on this: Generating OData Service With Auto-Exposure [page 19]
Procedure
If you finally run the app in the SAP Fiori Launchpad, the list reporting app provides you with extended
functionality - without any further (configuration) steps (no service activation required). The resulting UI
screen displays all added fields – as shown in the figure below.
Metadata extenstions enable you to add customer-specific annotations to SAP's CDS entities. Note that these
changes do not result in modifications.
Definition
A metadata extension is a development object that provides CDS annotations in order to extend the CDS
annotations used in a CDS entity. The standard ABAP Workbench functions (transport, syntax check,
activation, and so on) are supported.
Use
Metadata extensions enable you to write the annotations for a CDS entity in a different document to separate
them from the CDS entity.
Overview
To use a metadata extension for a CDS entity, you have to consider the following conditions:
1. In the definition of the CDS entity, the @Metadata.allowExtensions annotation with the value true is
added. This annotation explicitly allows the use of metadata extensions.
2. In the metadata extension, you have to define the name of the CDS entity to be annotated in the annotate
view statement.
3. In the Switch Framework, metadata extensions are switchable.
Advantages
You can benefit from the following advantages using metadata extensions:
1. Separation of Concerns: Separating the metadata specified in the annotations from the implementation
of the entity:
○ Improves the readability of the source code
○ Simplifies the development and maintenance of the CDS entity
In addition, the metadata can be developed and updated independently of the data definition.
2. ABAP Dictionary-independent activation: When activating a CDS entity, the metadata extensions will be
ignored. This results in the following advantages:
○ It reduces the number of ABAP Dictionary (mass) activations required to develop and maintain the
CDS entity.
○ It speeds up the overall development process.
○ It facilitates changing the metadata of a CDS entity in a running system, thereby reducing downtime.
3. Modification-free enhancements: Customers, partners, and industries can customize the metadata
without modifying the CDS entity.
In addition, metadata extensions are switchable. This means, the metadata can be specifically enabled or
disabled depending on the use case.
Activation
In general, in a metadata extension only those annotations are permitted that do not affect the ABAP
Dictionary activation/generation or the activation/generation of secondary objects (for example, OData
services). For example, the ABAP annotation @EndUserText and the component-specific annotations @UI can
be specified in metadata extensions. A syntax error occurs if annotations that are not permitted are specified.
The metadata contained in metadata extensions is only available to consumption clients that access the CDS
entity metadata using the ABAP API CL_DD_DDL_ANNOTATION_SERVICE. In this case, metadata in the
metadata extensions is merged together with the metadata in the CDS entity and also with the metadata that
is inherited from underlying entities (and metadata extensions) in the entity hierarchy.
Related Information
Object Model
Adding Field and Action Control [page 189]
Data Provisioning
Using Virtual Elements in CDS [page 206]
Enabling Text and Fuzzy Searches in SAP Fiori Apps [page 259]
UI Semantics
Defining Text Elements [page 271]
This topic treats the concept of field and action control in the context of SAP Fiori application development for
transactional use cases.
Field and action control is a means that you can provide as information to the service on how data has to be
displayed for consumption in the SAP Fiori UI.
In general, the following characteristics are relevant when providing field control:
● Read-only: - Will the user be allowed to change the value of a field (or a node instance)?
● Mandatory: - Must the user provide a value?
● Hidden: - Should a field be available for consumption in the UI?
Note
We do not cover this characteristics in this topic since the relevant information is provided by...
The field and action control can relate to individual properties (node attributes in BOPF) or a whole entity
(business object node instance in BOPF).
● Static - The field control information is valid for all instances of a business object node, regardless of their
state. For example, consider a field PAID in an invoice scenario that is always read-only since it can only be
changed by an action, not directly by the consumer after an update procedure.
More on this: Static Field Control [page 190]
● Dynamic - The field (and action) control information depends on the state of the node instances. For
example, the field COMMENTS should be read-only if the invoice‘s PAID attribute is set to true.
More on this:
○ Dynamic Field and Entity Control [page 194]
○ Dynamic Action Control [page 201]
Caution
If you use the Referenced Data Source (RDS) option for OData service creation, it is important that you
always regenerate your gateway project in transaction SEGW after you add, change, or remove field or
action control in the consumer views contained in the project.
Here we explain how you can implement static field control in CDS views.
Overview
In a typical transactional scenario, you have to implement so-called business object CDS views when modeling
business data. Such views are required for business object generation on the basis of the BOPF framework. To
provide static field control for your application, you have to add the appropriate CDS annotations in the
corresponding business object view - in fact, for both the VIEW and the ELEMENT scope. Using annotations with
the VIEW scope, you define the field control that is related to the whole entity. You thus specify at the business
object node level whether each node instance is enabled for creation, update, or deletion. When you add
annotations with the ELEMENT scope, you have the option to define the field control for each individual view
field and specify the field control at the attribute level of the corresponding business object node. If no such
field control annotations are explicitly added to the view, the default value (@ObjectModel.readOnly:
false) is assumed.
Field control annotations can be restricted in the consumption view. This means, you can overwrite read-only
value and change it from false (as defined in the BO view) to true (in the consumption view).
The annotations mentioned above are used in a business object CDS view (in our example:
ZDEMO_I_SalesOrder_TX) to define that instances of a business object node can be created and updated,
but not deleted.
...
@ObjectModel.transactionalProcessingEnabled: true
@ObjectModel.writeActivePersistence: 'ZTAB_SO'
@ObjectModel.createEnabled: true
@ObjectModel.deleteEnabled: false
@ObjectModel.updateEnabled: true
The business object CDS view from the sample code above is used for generating the corresponding sales
order business object. As you can see in the figure below, the field control that is related to the whole entity is
defined accordingly at the business object’s node level by the properties Create/Update/Delete Enabled.
BO editor with properties of the business object node corresponding to the CDS view
@ObjectModel.readOnly: true/false If this annotation has the value true, the annotated ele
ment must not be updated by the consumer.
Example
For the business object CDS view from the sales order example above, some field control annotations are used
to restrict properties of particular fields. Here, the element BusinessPartner cannot be modified, whereas
the value of the elements CurrencyCode, GrossAmount, NetAmount, and BillingStatus can be created or
updated. The key element SalesOrder is mandatory, that is, the property must contain a value.
...
@ObjectModel.updateEnabled: true
@ObjectModel.readOnly: true
SalesOrder.businesspartner as BusinessPartner,
@ObjectModel.readOnly: false
SalesOrder.currencycode as CurrencyCode,
@ObjectModel.readOnly: false
SalesOrder.grossamount as GrossAmount,
@ObjectModel.readOnly: false
SalesOrder.netamount as NetAmount,
@ObjectModel.readOnly: true
SalesOrder.billingstatus as BillingStatus,
...
}
The field control annotations restrict the attributes of the corresponding business object node. In the BO
editor, these attributes are listed in the Properties tab.
You can use field control annotations in the consumption view to restrict the values for static field control that
have been specified at the BO view level. In other words, you can overwrite the read-only value and change it
from false (in the BO view) to true (in the consumption view).
Remember
CDS Rule: Remember to double-maintain the annotations that have the VIEW scope. In CDS views, only the
annotations with ELEMENT scope are inherited from the business object view.
...
-- Repeated annotations from BO view – VIEW scope
@ObjectModel.createEnabled: true
@ObjectModel.deleteEnabled: false
@ObjectModel.updateEnabled: true
-- Consumption view
define view ZDEMO_C_SalesOrder_TX
@UI...
Document.CurrencyCode, -- inherits field control value
@UI...
@ObjectModel.readOnly: true -- restricts to non-editable field
Document.GrossAmount,
@UI...
@ObjectModel.readOnly: true -- restricts to non-editable field
Document.NetAmount,
@UI...
Document.BillingStatus
}
Related Information
In this chapter, we explain how you can define dynamic fields and entities (such as business object nodes) in
CDS views using ABAP CDS annotations and then implement dynamic field and entity control using a BOPF
determination.
Overview
Dynamic fields and entities allow you to control the visibility and changeability of fields or the entire business
object nodes depending on the value selected from another field. In the context of the ABAP programming
model for SAP Fiori, the field and entity control serve as a way to provide information to the OData service in a
transactional scenario about how data has to be displayed for consumption on the SAP Fiori UI. In particular,
when using BOPF business objects, the field and entity control information is dependent on the state of the
node instances. In this context, the field and entity control can in this context relate to the individual properties
(node attributes of the business object) or an entire entity (business object node).
Example
The following app manages invoices. Each invoice has three properties which are the invoice ID, the payment
status, and the comments provided. In our example, the fields Invoice ID and Comments should be read-only if
the invoice’s Paid attribute is set to true.
The ID and the comments fields are read-only for a paid invoice
In a typical transactional scenario, you must implement business object (BO) views when modeling business
data. The following steps are then required to provide dynamic field (or entity) control to the data model:
1. Adding annotations for dynamic field (or entity) control in the BO view
2. Activating the data definition object that includes the CDS BO view
3. Implementing the (automatically) generated property determination ACTION_AND_FIELD_CONTROL.
To enable dynamic field control for your application, you must add the appropriate CDS annotations with the
value 'EXTERNAL_CALCULATION' in the relevant business object view - either for the VIEW or the ELEMENT
scope. Using annotations with the VIEW scope, you define the entity control that is related to the whole entity
(business object node instance). You thus specify at the business object node level whether each node
instance is enabled for update, or deletion. When you add annotations with the ELEMENT scope, you have the
option to define the field control for each individual view field and specify the dynamic fields at the attribute
level of the corresponding business object node.
Dynamic Entity Control at the Business Object Node Level (VIEW Scope)
The following CDS annotations (specific to transactional processing) are relevant at the CDS view level when
defining dynamic entity control:
@ObjectModel: {
transactionalProcessingEnabled: true,
...
createEnabled: true | false -- no dynamic entity control
support for creation operations
deleteEnabled: true | false | 'EXTERNAL_CALCULATION'
updateEnabled: true | false | 'EXTERNAL_CALCULATION'
...
}
define view <ViewName>
as select from <data_source>
{
...
}
Dynamic Field Control at the Business Object Attribute Level (ELEMENT Scope)
The following CDS annotations at the element level of the CDS data model are relevant when defining dynamic
field control:
...
@ObjectModel.mandatory: true | false | 'EXTERNAL_CALCULATION'
<view.another_element>
...
}
Remember
Within a CDS view (BO view), you have the option to define both the dynamic field control (with the
ELEMENT scope) and the dynamic entity control (with the VIEW scope). You can also add the dynamic field
annotation with the value 'EXTERNAL_CALCULATION' to multiple view elements.
After you activate the data definition that defines the relevant CDS BO view, the BOPF framework automatically
generates a property determination with the name ACTION_AND_FIELD_CONTROL for the business object in
question. This determination is used to implement the field (or entity) control for each element (or each node
property) that is annotated with the value 'EXTERNAL_CALCULATION'.
Note
If the CDS BO View is included in a SEGW project with RDS, you have to regenerate the GW project to
enable the feature control. Only then are the auxiliary fields delete_mc, invoiced_mc etc. available in the
MPC class.
The generated determination class that is assigned to the business object node serves as a code exit for
implementing the BOPF determination contract. This contract requires a redefinition of the method /bobf/
if_frw_determination~execute.
Method Description
The relevant methods for setting properties of entire entities (BO nodes) are:
Method Description
Example
@AbapCatalog.sqlViewName: 'ZDEMO_I_INV_V'
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Invoices'
@ObjectModel: {
-- Annotations for transactional processing
semanticKey: 'Invoice',
compositionRoot: true,
transactionalProcessingEnabled: true,
createEnabled: true,
You can choose the Properties tab to view the properties of each element (attribute) related to the business
object created.
Generated BO properties
method /BOBF/IF_FRW_DETERMINATION~EXECUTE.
" The invoice's data is typed with BO node's combined table type
data lt_invoice_data type ztdemo_i_invoice_tp.
" (1) Retrieve the data of the invoice's node instance
io_read->retrieve(
EXPORTING
iv_node = is_ctx-node_key " uuid of the node instance
it_key = it_key " keys given to the determination
IMPORTING
et_data = lt_invoice_data ). " itab with invoice’s node data
" (2) Create a property helper object
data(lo_property_helper) = new /bobf/cl_lib_h_set_property( io_modify =
io_modify
is_context = is_ctx ).
" (3 ) Set the attribute "comments" to read-only for all paid invoices
loop at lt_invoice_data into data(ls_invoice_data)
where paid = abap_true.
lo_property_helper->set_attribute_read_only(
iv_attribute_name = zif_demo_i_invoice_tp_c=>sc_node_attribute-
zdemo_i_invoice_tp-comments
iv_key = ls_invoice_data-key ).
endloop.
endmethod.
Related Information
In this chapter, we explain how you can provide dynamic action control by using BOPF property
determinations.
Overview
From the BOPF perspective, field properties and action properties are very similar: they are both to be
implemented in the same property determination ACTION_AND_FIELD_CONTROL. In both cases, the property
helper class /BOBF/CL_LIB_H_SET_PROPERTY is used to set the relevant field or action control information.
When using business objects, both the field and the action control information depends on the state of the
node instances. Therefore, the action control can relate to an entire business object node or individual node
attributes.
Example
The following example app is used to manage invoices. Users can change the payment status for individual
invoices without having to switch to edit mode. The action Set to PAID is disabled for all paid invoices, since the
action control information is related to the attribute Paid.
Action enabled
Action disabled
In a typical transactional scenario, you must implement business object (BO) views when modeling business
data. Based on this, the following steps are then required to provide dynamic action control to the data model:
1. Creating, configuring, and implementing the BO-specific action - if you have not yet already done so.
2. Reactivating the business object - if necessary.
3. Implementing the determination class for the property determination ACTION_AND_FIELD_CONTROL.
Sice this step is already described in detail in other documentation, we will confine ourselves to referring to the
relevant topics.
Related Information
● Adding a New BOPF Action [page 96]
● Enabling Actions for OData Consumption [page 101]
●
To accept the most recent changes to the business object, you must reactivate it. You can then use the
generated property determination ACTION_AND_FIELD_CONTROL to implement the dynamic action control.
The created determination class that belongs to the business object node serves as a code exit for
implementing the BOPF determination contract. This contract requires a re-definition of the method /bobf/
if_frw_determination~execute. In other words: Each determination in BOPF must implement the
execute method of the determination interface /BOBF/IF_FRW_DETERMINATION.
Method SET_ACTION_ENABLED
Signature
importing IV_ACTION_KEY type /BOBF/CONF_KEY
Parameters
Parameter Description
IV_ACTION_KEY Key of the BOPF action for which the property is to be set
IV_KEY Key of the business object node instance for which the property is to be set
Example
To make the action available for consumption in an OData service, it is neccesary to configure the exporting
type. For further information, see: Enabling Actions for OData Consumption [page 101]
Each action in BOPF must implement the execute method of the action interface /BOBF/IF_FRW_ACTION.
The listing below is used to implement the SET_PAID action.
method /BOBF/IF_FRW_ACTION~EXECUTE.
" The invoice's data is typed with BO node's combined table type
data lt_invoice_data type ztdemo_i_invoice_tp.
" READING BO data ----------------------------------------------
" Retrieve the data of the requested node instance
io_read->retrieve(
EXPORTING
iv_node = is_ctx-node_key
it_key = it_key
IMPORTING
et_data = lt_invoice_data ).
" WRITING BO data ---------------------------------------------
LOOP AT lt_invoice_data ASSIGNING FIELD-SYMBOL(<s_invoice>).
" Set the attribue paid to new value
<s_invoice>-paid = abap_true. " PAID
" Update the changed data (payment status) of the relevant node instance
This property determination class calls the set_action_enabled method for setting the new property of the
action SET_PAID.
Related Information
This topic addresses the use of virtual elements in CDS in the context of SAP Fiori application development for
transactional use cases.
For some business use cases, it may be necessary to add new fields to the data model of an application and to
calculate their values using ABAP resources. Virtual elements come into play if these fields are not provided as
part of the original persistence data model or cannot be easily integrated in CDS so that their values can be
calculated directly on SAP HANA.
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.
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.
You can use the concept of virtual elements to implement the following use cases:
Example
The UI of the following sales order app provides an additional field GrossAmountWithDiscount for each sales
order item, which is not part of the persistence data model. The values of this field are calculated using the
ABAP code exit API for handling virtual elements. In our example, the values of this virtual field provide a
reduced gross amount of each sales order item. The discount depends on the gross amount volume: If the
gross amount is greater than EUR 1,000.00, the discount is calculated, for example, by the formula:
(ConvertedGrossAmount - 1,000.00) * 0.1. This leaves a remaining amount to pay of 1,000.00 +
(ConvertedGrossAmount - 1,000.00) * 0.9.
The following steps are relevant for providing virtual elements to the CDS data model:
1. Adding the virtual element and corresponding annotations in the relevant consumption CDS view.
More on this: Adding Annotations for Virtual Elements [page 208]
2. Creating and implementing ABAP classes that serve as a code exit for implementing the virtual element
contract.
More on this: Implementing ABAP Code Exits for Virtual Elements [page 212]
In case of implementing filters for virtual elements, you need to create conditions for the substitution of
filters on virtual elements.
More on this: Creating Conditions with the Simple Condition Factory [page 218]
3. Creating exception classes for handling application-specific exceptions.
More on this: Creating Application-Specific Exception Classes [page 231]
When you define code exits, the following CDS annotations are relevant at the ELEMENT level of the CDS data
model:
For the calculation of the field values in CDS views, the following @ObjectModel annotations are required:
Note
When defining a virtual element, the data type of the element must be specified.
For the filtering of field values, the relevant view element must use the @ObjectModel.filter annotation:
For the sorting of field values, the relevant view element must use the @ObjectModel.sort annotation:
virtualElement Semantics:
Note
Virtual elements may only be defined within the ELEMENT scope at CDS
consumption view level.
virtualElementCalculatedBy Semantics:
: 'ABAP:<code_exit_class>'
Defines the ABAP class that calculates the value of the virtual element
This annotation requires that the view element in question is also annotated with
@ObjectModel.virtualElement: true.
Engine Behavior:
ABAP runtime invokes the specified function (ABAP code exit class) for calculat
ing the value of the virtual element.
filter.transformedBy: Semantics:
'ABAP:<code_exit_class>'
Defines the ABAP class that transforms the filter criteria specified for the anno
tated element to the filter criteria of other elements
This transformation class is assigned by the technical name of the ABAP class
<code_exit_class> that implements the code exit interface
IF_SADL_EXIT_FILTER_TRANSFORM.
Virtual fields are exposed as filterable through OData if they have specified such a
transformation class.
Note
This annotation may be used only for virtual elements and only at CDS con
sumption view level.
Engine Behavior:
SADL framework exposes the annotated element as filterable and invokes the
given transformation class at runtime.
sort.transformedBy: Semantics:
'ABAP:<code_exit_class>'
Defines the ABAP class that transforms the sort criteria specified for the anno
tated view element to sort criteria of other view elements
This transformation class is assigned by the technical name of the ABAP class
<code_exit_class> that implements the code exit interface
IF_SADL_EXIT_SORT_TRANSFORM.
Virtual fields are exposed as sortable through OData if they have specified such a
transformation function.
Note
This annotation may be used only for virtual fields and only at CDS consump
tion view level.
Engine Behavior:
SADL framework exposes the annotated field as sortable and invokes the given
transformation class at runtime.
Example
The source code below defines a simple CDS view ZDEMO_C_SOrderItem_VF for processing sales order
items. This view is implemented as a consumption view with the predefined view
SEPM_I_SalesOrderItem_E (that originates from the EPM demo application) that serves as the data source.
The select list includes a virtual element GrossAmountWithDiscount, which is not foreseen as a part of the
persistence data model, for each sales order item. The values of the corresponding field are calculated using
the code exit ABAP class ZCL_CALCULATION_DISCOUNT. Additional classes (ZCL_FILTER_DISCOUNT and
ZCL_SORT_DISCOUNT) are used to implement the filtering and sorting of the calculated field. In our example,
the values of this calculated field provide a reduced gross amount of each sales order item. In addition, we add
an additional field ConvertedGrossAmount to provide the gross amount in EUR as the target currency. For
this purpose, the currency conversion procedure is included in the source code of the CDS view.
@AbapCatalog.sqlViewName: 'ZDEMO_SOI_VF'
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Sales Order Item - Virtual Fields'
@Metadata.allowExtensions: true
@Search.searchable : true
@OData.publish: true
@Search.defaultSearchElement: true
key Item.SalesOrder as SalesOrder,
@Semantics.currencyCode: true
Item.TransactionCurrency as TransactionCurrency,
@Semantics.amount.currencyCode: 'TransactionCurrency'
Item.GrossAmountInTransacCurrency as GrossAmount,
-- Virtual element
@ObjectModel.readOnly: true
@ObjectModel.virtualElement:true
@ObjectModel.virtualElementCalculatedBy: 'ABAP:ZCL_CALCULATION_DISCOUNT'
@ObjectModel.filter.transformedBy: 'ABAP:ZCL_FILTER_DISCOUNT'
@ObjectModel.sort.transformedBy: 'ABAP:ZCL_SORT_DISCOUNT'
CURRENCY_CONVERSION(
amount => Item.GrossAmountInTransacCurrency,
source_currency => Item.TransactionCurrency,
target_currency => cast( 'EUR' as abap.cuky ),
exchange_rate_date => cast( '20170101' as abap.dats ),
error_handling => 'SET_TO_NULL' ) as ConvertedGrossAmount
-- Currency conversion end
}
Prerequisites
The calculation of field values requires that:
● The following virtual element annotations are added to the corresponding element at the level of the CDS
consumption view:
@ObjectModel.readOnly: true
@ObjectModel.virtualElement: true
@ObjectModel.virtualElementCalculatedBy: 'ABAP:<code_exit_class>'
Note
● An ABAP code exit class is created for implementing the code exit interface
IF_SADL_EXIT_CALC_ELEMENT_READ.
The code exit contract for calculation of the virtual value requires the implementation of both the methods
GET_CALCULATION_INFO and CALCULATE of the code exit interface IF_SADL_EXIT_CALC_ELEMENT_READ.
Example
The method GET_CALCULATION_INFO provides the list of fields required for data calculation:
● The field CONVERTEDGROSSAMOUNT saves the values of the gross amount for sales order items
calculated in EUR (target currency).
● The field GROSSAMOUNTWITHDISCOUNT is used to save the calculated gross amount values under
consideration of specific discount rules.
As shown in the listing below, the method GET_CALCULATION_INFO raises a predefined exception
entity_not_known that is passed to the parameter TEXTID of the instance constructor of the
application-specific exception class ZCX_CALC_EXIT.
The actual calculation of the reduced gross amount is implemented within the method calculate. The
discount depends on the gross amount volume and starts for a gross amount greater than 1,000.00 EUR.
The customer receives a 10% discount on the delta between the gross amount and 1,000.00 EUR. The
gross amount with the discount is calculated with the formula: 1,000.00 + (ConvertedGrossAmount
– 1,000.00) * 0.9.
PUBLIC SECTION.
INTERFACES:
if_sadl_exit_calc_element_read.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
METHOD if_sadl_exit_calc_element_read~get_calculation_info.
IF iv_entity <> 'ZDEMO_C_SORDERITEM_VF'.
RAISE EXCEPTION TYPE zcx_calc_exit EXPORTING textid =
zcx_calc_exit=>entity_not_known.
ENDIF.
IF line_exists( it_requested_calc_elements[ table_line =
'GROSSAMOUNTWITHDISCOUNT' ] ).
APPEND 'CONVERTEDGROSSAMOUNT' TO et_requested_orig_elements.
ENDIF.
ENDMETHOD.
METHOD if_sadl_exit_calc_element_read~calculate.
ENDMETHOD.
ENDCLASS.
Preview
Prerequisites
The filter transformation requires that:
● The following filter annotation is added to the corresponding element at the level of the CDS consumption
view:
@ObjectModel.filter.transformedBy: 'ABAP:<code_exit_class>'
Remember
● An ABAP class is created for implementing the code exit interface IF_SADL_EXIT_FILTER_TRANSFORM.
Implementation Steps
The code exit contract for filter transformation requires the implementation of the method MAP_ATOM of the
code exit interface IF_SADL_EXIT_FILTER_TRANSFORM.
Note
The substitution of the condition with the method MAP_ATOM must not include virtual elements.
Example
The implementation of the method MAP_ATOM in the listing below demonstrates how you can transform
filter conditions specified for the annotated (virtual) view element GROSSAMOUNTWITHDISCOUNT to filter
criteria of other view elements. In other words, we have to replace the filter condition on the calculated field
GROSSAMOUNTWITHDISCOUNT with a condition for the original persistent field CONVERTEDGROSSAMOUNT.
For further information about building complex conditions, see Creating Conditions with the Simple
Condition Factory [page 218].
Preview
Prerequisites
The sorting of field values requires that:
● The following sort annotation is added to the corresponding element at the level of the CDS consumption
view:
@ObjectModel.sort.transformedBy: 'ABAP:<code_exit_class>'
Remember
● An ABAP class is created for implementing the code exit interface IF_SADL_EXIT_SORT_TRANSFORM.
Implementation Steps
The code exit contract for sort transformation requires the implementation of the method MAP_ELEMENT of the
code exit interface IF_SADL_EXIT_SORT_TRANSFORM.
Example
Complex conditions can be built with the simple condition factory. This factory concatenates expressions with
relational and logical operators; both of them represented by methods.
Context
Filtering on virtual elements requires the transformation of the given filter condition into a corresponding
condition that does not use any virtual elements for the filter. The implementation of the substituting condition
is done with the method IF_SADL_EXIT_FILTER_TRANSFORM~MAP_ATOM.
The construction of this condition is most easily done with the simple condition factory created by the method
CREATE_SIMPLE_COND_FACTORY. This static method is called by the class
CL_SADL_COND_PROV_FACTORY_PUB. You can build complex conditions with the simple condition factory by
concatenating them with relational and logical operators.
Procedure
1. Create a simple condition factory by calling the static method CREATE_SIMPLE_COND_FACTORY on the
public condition provider class CL_SADL_COND_PROV_FACTORY_PUB.
DATA(lo_cfac) = cl_sadl_cond_prov_factory_pub=>create_simple_cond_factory( ).
Method Description
element Use this method to initialize a condition. It defines the first operand represented by a
non-virtual element of the CDS view. Methods of relational operators are executed on its
returning value ro_element by using methods of relational operators.
For the importing parameter iv_element, enter the name of the element that repre
sents the operand 'FIELD1' in the condition.
ro_condition = lo_cfac->true( ).
ro_condition = lo_cfac->false( ).
3. In case you used the method ELEMENT in the previous step, choose one of the methods for relational
operators to set the operands FIELD1 (iv_element) and X (iv_value) into relation with each other.
For the importing parameter iv_value, enter the reference value for the relation (for
example a numeric value like 72).
For the importing parameter iv_value, enter the reference value for the relation (for
example a numeric value like 72).
less_than Use this method to build a condition like FIELD1 < 72.
For the importing parameter iv_value, enter the reference value for the relation (for
example a numeric value like 72).
greater_than Use this method to build a condition like FIELD1 > 72.
For the importing parameter iv_value, enter the reference value for the relation (for
example a numeric value like 72).
covers_pattern Use this method to build a condition like FIELD1 covers the pattern of ABCDEF.
For the importing parameter iv_value, enter the reference value for the relation (for
example a string value like ABC*).
not_covers_pattern Use this method to build a condition like FIELD1 does not cover the pattern of ABCDEF.
For the importing parameter iv_value, enter the reference value for the relation (for
example a string value like *DEF).
is_not_null Use this method to build a condition like FIELD1 is not null.
For the importing parameter iv_low and iv_high, enter the values that provide the
lower limit and upper limit (for example 120) of the range (for example numeric values
like 72 and 120).
is_not_between Use this method to build a condition like not 72 ≤ FIELD1 ≤ 120.
For the importing parameter iv_low and iv_high, enter the values that provide the
lower limit and upper limit of the range (for example numeric values like 72 and 120).
4. You can concatenate the conditions built by the previous steps with the methods of the logical operators
AND, OR, NEGATED, and EXISTS.
and Use this method to concatenate two conditions if you want the concatenated condition
to be true if both expressions (the preceding and the succeeding expression) are true.
or Use this method to concatenate two conditions if you want the concatenated condition
to be true if either of the expressions (the preceding or the succeeding expression) is
true.
ro_condition = lo_condition1->negated( ).
This condition expresses the same content as a condition with the opposite relational
operator.
exists Use this method if the preceding condition refers to an associated CDS entity with car
dinality "ONE TO MANY". The condition is true if there are entries in the source entity
that have associated entries that satisfy the condition.
For the importing parameter (iv_name) enter an alias for the target entity that you
have chosen in the preceding condition.
For the importing parameter (iv_path) enter the association path that is declared in
the CDS entity definition.
Results
You can continuously combine conditions with relational and logical operators:
Tip
Improve the readability of your condition by predefining the first operand before you use it in the condition:
This condition is true for all field values of FIELD1 that are less than 100.
The following interfaces define methods that are used to construct complex conditions with the simple
condition factory.
The methods of this interface are used to construct complex conditions with the simple condition factory. It
creates objects that are set into relation with input values by relational operators.
This method provides the start of a complex condition. It defines the first operand of a relation.
Signature
Parameters
IV_NAME Name of a non-virtual element that is set into relation with a value by the methods of rela
tional operators.
RO_ELEMENT Operand of the condition represented by a CDS element. The methods of relational opera
tors can be executed on this object.
Signature
Parameters
RO_CONDITION Complete condition which is always either true or false. It can be used for the substitution of
filters for virtual elements or further concatenated by methods of the interface
IF_SADL_COND_PROVIDER_GENERIC.
The methods of this interface are used to construct complex conditions with the simple condition factory. They
provide relational operators to set operands into relation.
The method element of the interface IF_SADL_SIMPLE_COND_FACTORY returns the first operand of a
relation. The following methods operate on this returning value.
All of the following methods return an object pointing to IF_SADL_COND_PROVIDER_GENERIC. The methods
of this interface can thus be used consecutively.
These methods set two operands into relation with each other. The condition is considered to be true if the
value of the first operand is equal to the value of the second operand.
Signature
Parameters
IV_VALUE Value of the second operand that is set into relation with the first operand by EQUALS or
NOT_EQUALS
RO_CONDITION Complete condition. It can be used for the substitution of filters for virtual elements or fur
ther concatenated by methods of the interface IF_SADL_COND_PROVIDER_GENERIC.
These methods set two operands into relation with each other. The condition is considered to be true if the
value of the first operand is less than or greater than the value of the second operand.
Signature
Parameters
IV_VALUE Value of the second operand that is set into relation with the first operand by LESS_THAN
or GREATER_THAN.
RO_CONDITION Complete condition. It can be used for the substitution of filters for virtual elements or fur
ther concatenated by methods of the interface IF_SADL_COND_PROVIDER_GENERIC.
Example
The following code example illustrates how the method greater_than is implemented. The example is
taken from a scenario that processes sales orders and sales order items. The condition is implemented in a
code exit class for a virtual element.
Assume we have a simple CDS consumption view that processes sales order items. The select list includes
a virtual element RECEIVESDISCOUNT that evaluates to true or false, depending on the gross amount of
METHOD if_sadl_exit_filter_transform~map_atom.
IF iv_element <> 'RECEIVESDISCOUNT'.
RAISE EXCEPTION TYPE zcx_filter_exit EXPORTING textid =
zcx_filter_exit=>element_not_expected.
ENDIF.
CASE iv_operator.
WHEN if_sadl_exit_filter_transform~co_operator-equals.
DATA(lo_cfac) =
cl_sadl_cond_prov_factory_pub=>create_simple_cond_factory( ).
DATA(amount) = lo_cfac->element( 'CONVERTEDGROSSAMOUNT' ).
IF iv_value = abap_true.
ro_condition = amount->greater_than( 1000 ).
ELSEIF iv_value = abap_false.
ro_condition = amount->less_than_or_equals( 1000 ).
ELSE.
RAISE EXCEPTION TYPE zcx_filter_exit.
ENDIF.
WHEN OTHERS.
RAISE EXCEPTION TYPE zcx_filter_exit.
ENDCASE.
ENDMETHOD.
These methods set two operands into relation with each other. The condition is considered to be true if the
value of the first operand is less than or equal to orgreater than or equal to the value of the second operand.
Signature
Parameters
IV_VALUE Value of the second operand that is set into relation to the first operand by
LESS_THAN_OR_EQUALS or GREATER_THAN_OR_EQUALS.
RO_CONDITION Complete condition. It can be used for the substitution of filters for virtual elements or fur
ther concatenated by methods of the interface IF_SADL_COND_PROVIDER_GENERIC.
These methods provide a condition that is true if the first operand is (not) null.
Signature
Parameters
RO_CONDITION Complete condition. It can be used for the substitution of filters for virtual elements or fur
ther concatenated by methods of the interface IF_SADL_COND_PROVIDER_GENERIC.
These methods provide a condition that is true if the first operand covers the pattern or false if the first
operand does not cover the pattern of the second operand respectively.
Signature
Example
The following code example illustrates how the method COVERS_PATTERN is implemented. The example is
taken from a scenario that processes sales orders and sales order items. The condition is implemented in a
code exit class for a virtual element.
Assume we have a simple CDS consumption view that processes sales order items. The select list includes
a virtual element LIMITEDEDITION that can take the values Christmas, Spring, Holiday, and
Unlimited, depending on the product ID of the item. The following code snippet shows the
implementation of the method IF_SADL_EXIT_CALC_ELEMENT_READ~CALCULATE, which implements
this calculation of the virtual element:
METHOD if_sadl_exit_calc_element_read~calculate.
CHECK NOT it_original_data IS INITIAL.
DATA lt_calculated_data TYPE STANDARD TABLE OF zdemo_c_soi_vf_condition
WITH DEFAULT KEY.
MOVE-CORRESPONDING it_original_data TO lt_calculated_data.
LOOP AT lt_calculated_data ASSIGNING FIELD-SYMBOL(<ls_calculated_data>).
IF <ls_calculated_data>-product CP 'HT-111*'.
<ls_calculated_data>-limitededition = 'Christmas'.
ELSEIF <ls_calculated_data>-product CP 'HT-107*'.
<ls_calculated_data>-limitededition = 'Spring'.
ELSEIF <ls_calculated_data>-product CP 'HT-12*'
OR <ls_calculated_data>-product CP 'HT-15*'.
The virtual element can be filtered. The filter condition must be translated into a condition for an element of
the original persistent data model. As can be seen in the following code, the element PRODUCT is used for
this in the method IF_SADL_EXIT_FILTER_TRANSFORM~MAP_ATOM. The method of the relational
operator in this case is COVERS_PATTERN.
METHOD if_sadl_exit_filter_transform~map_atom.
IF iv_element <> 'LIMITEDEDITION'.
RAISE EXCEPTION TYPE zcx_filter_exit EXPORTING textid =
zcx_filter_exit=>element_not_expected.
ENDIF.
CASE iv_operator.
WHEN if_sadl_exit_filter_transform~co_operator-equals.
DATA(lo_cfac) =
cl_sadl_cond_prov_factory_pub=>create_simple_cond_factory( ).
DATA(product) = lo_cfac->element( 'PRODUCT' ).
CASE iv_value.
WHEN 'Christmas'.
ro_condition = product->covers_pattern( 'HT-111*' ).
WHEN 'Spring'.
ro_condition = product->covers_pattern( 'HT-107*').
WHEN 'Holiday'.
ro_condition = product->covers_pattern( 'HT-12*' )->or(
product->covers_pattern( 'HT-15*' ) ).
WHEN 'Unlimited'.
ro_condition = product->not_covers_pattern( 'HT-111*' )->and(
product->not_covers_pattern( 'HT-107*' ) )->and(
product->not_covers_pattern( 'HT-12*' ) )->and(
product->not_covers_pattern( 'HT-15*' ) ).
WHEN OTHERS.
RAISE EXCEPTION TYPE zcx_filter_exit.
ENDCASE.
WHEN OTHERS.
RAISE EXCEPTION TYPE zcx_filter_exit EXPORTING textid =
zcx_filter_exit=>element_not_expected.
ENDCASE.
ENDMETHOD.
Parameters
IV_VALUE Value of the second operand that is set into relation with the first operand by
COVERS_PATTER or NOT_COVERS_PATTERN.
RO_CONDITION Complete condition. It can be used for the substitution of filters for virtual elements or fur
ther concatenated by methods of the interface IF_SADL_COND_PROVIDER_GENERIC.
These methods provide a condition that is true if the value of the first operand is (not) between the values of
the importing parameters IV_LOW and IV_HIGH.
Parameters
IV_LOW Value of the lower boundary of the interval that is set into relation with the first operand by
BETWEEN or NOT_BETWEEN.
IV_HIGH Value of the upper boundary of the interval that is set into relation with the first operand by
BETWEEN or NOT_BETWEEN.
RO_CONDITION Complete condition. It can be used for the substitution of filters for virtual elements or fur
ther concatenated by methods of the interface IF_SADL_COND_PROVIDER_GENERIC.
Interface that provides concatenation methods to build complex conditions. It also provides methods that
connect conditions with logical operators.
This interface defines the following methods to concatenate conditions. The return value of these methods
point to the exact same interface that enables unlimited concatenation of conditions. The methods are
executed on objects pointing to IF_SADL_COND_PROVIDER_GENERIC.
These methods concatenate two conditions constructed by the simple condition factory.
AND operates like the logical operator "and". The concatenated condition is true if both conditions are true.
OR operates like the logical operator "or". The concatenated condition is true if either of the conditions is true
or if both conditions are true.
Signature
METHODS and
IMPORTING io_condition TYPE REF TO if_sadl_cond_provider_generic
RETURNING VALUE(ro_condition) TYPE REF TO if_sadl_cond_provider_generic.
METHODS or
IMPORTING io_condition TYPE REF TO if_sadl_cond_provider_generic
RETURNING VALUE(ro_condition) TYPE REF TO if_sadl_cond_provider_generic.
RO_CONDITION Complete condition. It can be used for the substitution of filters for virtual elements or fur
ther concatenated by methods of the interface IF_SADL_CON_PROVIDER_GENERIC.
Method negated
The method NEGATED reverses the truth content of the preceding condition.
It operates like the logical operator "not". The condition is true if the preceding expression is false and vice
versa.
Signature
METHODS negated
RETURNING VALUE(ro_condition) TYPE REF TO if_sadl_cond_provider_generic.
Parameters
RO_CONDITION Complete condition. It can be used for the substitution of filters for virtual elements or fur
ther concatenated by methods of the interface IF_SADL_CON_PROVIDER_GENERIC.
Method exists
The method EXISTS is used if filter conditions are substituted by conditions on non-virtual elements of
associated views with cardinality 1... n. In this case, it ensures that only those entries of the source entity are
retrieved for which entries of the filtered target entity exist.
Signature
METHODS negated
RETURNING VALUE(ro_condition) TYPE REF TO if_sadl_cond_provider_generic.
Parameters
IV_NAME Alias for the associated entity, in which the preceding condition is applied. This name needs
to match the navigation alias of the importing parameter iv_element, which is used for
the method ELEMENT of the preceding condition.
IV_PATH Name of the association in which the preceding condition is applied. The name of the asso
ciation is defined in the data definition of the source CDS entity. The path can either be an
association name or a concatenation of a predecessor path and an association name sepa
rated by a single dot.
RO_CONDITION Complete condition. It can be used for the substitution of filters for virtual elements or fur
ther concatenated by methods of the interface IF_SADL_CON_PROVIDER_GENERIC.
The following example illustrates how the method EXISTS is implemented. The example is taken from a
scenario that processes sales orders and sales order items. The condition is implemented in a code exit
class for a virtual element.
Assume we have a simple CDS consumption view ZDEMO_C_SO_VF_CONDITION that processes sales
orders. The select list includes a virtual element HASDISCOUNT that can take the values true and false.
These values depend on the gross amount of the sales order items in this sales order. The items, however,
are processed in an associated view, ZDEMO_C_VF_CONDITION with the alias_Items. This is why we need
a SELECT within the method IF_SADL_EXIT_CALC_ELEMENT_READ~CALCULATE to be able to use the
element from a foreign view for the calculation of the virtual element. The following code snippet shows the
implementation of the calculation for the virtual element HASDISCOUNT, which is defined in a view that
processes sales orders. The virtual element takes the value true if the gross amount of the sales order
items is greater than 1000.
METHOD if_sadl_exit_calc_element_read~calculate.
CHECK NOT it_original_data IS INITIAL.
DATA lt_calculated_data TYPE STANDARD TABLE OF zdemo_c_so_vf_condition
WITH DEFAULT KEY.
MOVE-CORRESPONDING it_original_data TO lt_calculated_data.
CHECK NOT lt_calculated_data IS INITIAL .
SELECT salesorder FROM zdemo_c_soi_vf_condition INTO TABLE
@DATA(lt_discount_items)
FOR ALL ENTRIES IN @lt_calculated_data
WHERE salesorder = @lt_calculated_data-salesorder AND
convertedgrossamount > 1000.
LOOP AT lt_calculated_data ASSIGNING FIELD-SYMBOL(<ls_calculated_data>).
IF line_exists( lt_discount_items[ salesorder = <ls_calculated_data>-
salesorder ] ).
<ls_calculated_data>-hasdiscount = abap_true.
ELSE.
<ls_calculated_data>-hasdiscount = abap_false.
ENDIF.
MOVE-CORRESPONDING lt_calculated_data TO ct_calculated_data.
ENDLOOP.
ENDMETHOD.
The virtual element can be filtered by the condition HASDISCOUNT eq true or HASDISCOUNT eq false This
filter condition must be translated into a condition for an element of the original, persistent data model.
This persistent element (CONVERTEDGROSSAMOUNT) is defined in the associated view of sales order items.
For this reason, you need the method EXISTS to implement the condition translation with the method
IF_SADL_EXIT_FILTER_TRANSFORM~MAP_ATOM.
METHOD if_sadl_exit_filter_transform~map_atom.
IF iv_element <> 'HASDISCOUNT'.
RAISE EXCEPTION TYPE zcx_filter_exit EXPORTING textid =
zcx_filter_exit=>element_not_expected.
ENDIF.
CASE iv_operator.
WHEN if_sadl_exit_filter_transform~co_operator-equals.
DATA(lo_cfac) =
cl_sadl_cond_prov_factory_pub=>create_simple_cond_factory( ).
DATA(amount) = lo_cfac->element( 'ITEM.CONVERTEDGROSSAMOUNT' ).
DATA(lo_condition) = amount->greater_than( 1000 )->exists( iv_name =
'ITEM' iv_path = '_Items' ).
IF iv_value = abap_true.
ro_condition = lo_condition.
ELSEIF iv_value = abap_false.
ro_condition = lo_condition->negated( ).
ENDCASE.
ENDMETHOD.
To handle application-specific exceptions in the context of virtual elements, you must create exception classes
that inherit from the generic SADL exit class CX_SADL_EXIT.
To explicitly raise a predefined exception, add, for example, the constant element_not_expected to the
exception class – as shown in the listing below.
The code exit class for virtual elements is a global ABAP class that implements the corresponding interface(s) -
according to the use case:
Interface that must be implemented by calculation classes annotated at the level of the CDS view element with
the @ObjectModel.virtualElement annotation.
This interface defines the following methods for implementing the field calculation:
Method GET_CALCULATION_INFO
Provides a list of all elements that are required for calculating the values of the virtual elements
This method is called by the SADL framework prior to the retrieval of data from the database to ensure that all
fields necessary for calculation are filled with data
Signature
raising CX_SADL_EXIT
Parameters
Parameter Description
IT_REQUESTED_CALC_E List of virtual elements that are requested by the client and are intended for field calculation
LEMENTS
IV_ENTITY Name of the CDS entity, such as a CDS view, that defines the relevant virtual elements
ET_REQUESTED_ORIG_E List of original persistent fields (in capital letters) that are used to calculate the virtual ele
LEMENTS ments
CX_SADL_EXIT Abstract exception class that can be used to return exceptions and messages related to the
processing of virtual element calculation
Method CALCULATE
This method is called by the SADL framework after data is retrieved from the database. The elements needed
for the calculation of the virtual elements are already filled in the data table passed to this method. The method
returns a table that contains the values of the requested virtual elements.
Note
Only elements of the same CDS entity (view) must be used for the calculation.
Note
Calculated fields cannot be used together with the grouping or the aggregation function.
Signature
raising CX_SADL_EXIT
Parameter Description
IT_ORIGINAL_DATA Table of original data that is filled with the original persistent field values that are used to
calculate the virtual elements.
IT_REQUESTED_CALC_E List of virtual elements that are requested by the client and are intended for field calculation
LEMENTS
CT_CALCULATED_DATA Table of calculated fields which correspond to the original data by index.
CX_SADL_EXIT Abstract exception class that can be used to return exceptions and messages related to the
processing of virtual element calculation.
Interface that must be implemented by filter transformation classes annotated at the level of the CDS view
element with the @ObjectModel.filter.transformedBy annotation
This interface defines the following method for implementing the filter transformation:
Method MAP_ATOM
Transforms filter conditions specified for the annotated view element to filter criteria of other view elements
This method is called by the SADL framework before data is retrieved from the database. Note that this
method is primarily intended for replacing filter conditions on virtual elements. However, it can also be used to
achieve better performance when filtering elements that have been calculated by means of CDS.
Signature
raising CX_SADL_EXIT_FILTER_NOT_SUPP
CX_SADL_EXIT
Parameter Description
IV_ENTITY Name of the CDS entity, such as the CDS view that defines the virtual elements in
question
IV_ELEMENT Name of the filter element, for example ‘FIELD1’ in the filter condition: FIELD1 =
77
RO_CONDITION Filter condition that replaces the condition of the annotated element
CX_SADL_EXIT_FILTER_NOT_SU Exception class from the SADL framework that throws an exception if the filter
PP operation is not supported
CX_SADL_EXIT Abstract exception class that can be used for returning exceptions and messages
related to the processing of virtual elements
Interface that must be implemented by sort transformation classes annotated at the level of the CDS view
element with the @ObjectModel.sort.transformedBy annotation
This interface defines the following method for implementing the sort transformation:
Method MAP_ELEMENT
Transforms the sort criteria specified for the annotated view element to sort criteria of other view elements
This method is called by the SADL framework before data is retrieved from the database.
Note
You can also use multiple elements to replace the sort criteria. In addition, you can change the sort order if
necessary.
Note
When using this sort transformation along with the grouping or aggregation function, you must ensure that
elements to be replaced are part of the requested elements (requeseted by a client). In addition, you must
annotate the element to be replaced with @Consumption.groupWith: ‘replacement_element’.
raising CX_SADL_EXIT
Parameters
Parameter Description
IV_ENTITY Name of the CDS entity, such as the CDS view that defines the virtual elements in
question
ET_SORT_ELEMENTS Table with replacement elements that will be used for sorting instead of the anno
tated element
For each element, it specifies whether the sort order must be kept or reversed.
CX_SADL_EXIT Abstract exception class that can be used to return exceptions and messages re
lated to the processing of virtual elements
We speak of temporal data whenever data properties depend on time, meaning that certain properties are only
valid during a specific validity period. If temporal data is stored in the database with table fields that define the
beginning and the end of the valid time frame, temporal data can be modeled in CDS entities and retrieved in
OData requests.
Note
To be able to retrieve data that is filtered by a certain date, the CDS views of the data model must be equipped
with annotations that mark the temporal date fields as filter references. Additionally, you can add an entity
annotation which triggers a default filter with the system date if no other filter date is applied by the user.
More on this: Adding Annotations for Full Temporal Exposure [page 239]
To pass the value of the custom query option to a view parameter, you have to add an annotation to the
parameter in the data model.
As soon as the data model is equipped with the relevant annotations, the temporal filtering can be applied by
using a custom query option, which is added to the URI. The value of the custom query option is used to find
the matching record for the query.
Temporal data is data that is time-dependent. The data properties are only valid during a specific validity
period. If temporal data is stored in the database with table fields that define the beginning and the end of the
valid time frame, temporal data can be modeled in CDS entities and retrieved in OData requests.
There are various scenarios in which data varies over time. Imagine a person moves and gets a new address or
think of an employee’s income, which increases from time to time. In this case, the properties of a data set (for
example an address or salary amount) have different values for each time frame in which they are valid. When
using temporal data, not only the current state of information is stored, but every version of the information
together with its validity period.
The data becomes temporal as soon as a timestamp is stored as part of the data set. Thus, the database table
requires fields (for example validfrom and validto) that specify the time frame in which the respective
properties are valid. To avoid losing old information, instead of overwriting a row with the current information, a
new row is attached to the data set. The valid times are stored in separate columns in the database to identify
the validity period of the relevant data. Each property change triggers the attachment of a new data set to keep
the information up-to-date without losing expired data. For every time instance in the past and present you
then find a matching set of data.
You can now retrieve and filter temporal data by validity dates. For this filtering, you can either use the system
date as a data reference to retrieve the current state of the data or a time travel query to retrieve data of
previously expired validity periods.
Example
A company stores information about employees. Some properties, however, are not static over time, but might
change during the work cycle of the employee, for example the job title or the department in which the
employee works.
The following table demonstrates the employee information that is dependent on time. There are two columns
identifying the beginning and end of the respective validity period.
Sue Bay works in Department D001 as Administrative Assistant during a specific time period: January 1, 1990
until June 30, 1999. Between July 1, 1999 and December 31, 2009 she works as Administrative Manager,
becoming Administrative Director on January 1, 2010 in a different department and changes to Department
D003 on December 1, 2011.
The example demonstrates that there can be more than one record related to one employee. However, by
restricting the data to one specific day, there is only one record which matches exactly one employee at one
specific point in time.
Database tables with temporal data cannot have a key which is only assigned to fields of one column. The value
of a single key can be used for several different records as every property change triggers an attachment of a
new record with the matching validity period. In this case, a single key field does not guarantee uniqueness.
Uniqueness is only achieved by a compound key, which includes one of the temporal date fields.
In the example above, the ID field is not an applicable unique key field for the temporal data set. Only by
combining the ID field with at least one of the temporal date fields is every record clearly identifiable. This
makes the key unique.
The following figure demonstrates how a compound key makes the record unique when dealing with temporal
data.
To be able to retrieve data that is filtered by a certain date, the CDS views of the data model must be equipped
with annotations that mark the temporal date fields as filter references. Additionally, you can add an entity
annotation which triggers a default filter with the system date if no other filter date is applied by the user.
More on this: Adding Annotations for Full Temporal Exposure [page 239]
To pass the value of the custom query option to a view parameter, you have to add an annotation to the
parameter in the data model.
More on this: Adding Annotations when Using a Temporal Parameter [page 243]
As soon as the data model is equipped with the relevant annotations, the temporal filtering can be applied by
using a custom query option, which is added to the URI. The value of the custom query option is used to find
the matching record for the query.
To enable temporal filtering by a custom query option, several annotations in the data model are required.
Prerequisites
If there are discontinuances between periods, for example breaks between two subsequent periods,
the output does not contain any data. The OData request then raises the regular exception “Not found”,
as there is no data in the data set matching the request. From a semantic point of view, the entity is
considered as nonexistent at the given point in time.
● If a time period has not expired yet the end of the validity period must be set to a sufficiently large value,
preferably the largest possible value, for example December 31, 9999.
Element Annotations
Context
The elements specifying the beginning of the validity period and the end of the validity period must be marked
as the reference for the temporal filter. This marking is done by two annotations that need to be added to the
elements.
Procedure
● Add @semantics.businessDate.from to the element that defines the beginning of the validity period.
● Add @semantics.businessDate.to to the element that defines the end of the validity period
Results
Whenever a temporal custom query option at=YYYYMMDD is used in an OData request, the rows in records are
filtered by the delivered value and only records with a time frame matching the temporal query option are
exposed.
Context
The cardinality of the target data source (which contains temporal data) is "TO MANY", as every record of the
source entity is related to one or more records of the dependent entity due to the additional temporal
dimension.
To reduce the cardinality of the target data source, when a temporal filter is used, the foreign key association
must use an @consumption annotation.
Procedure
…
define view <CdsConsumptionView>
as select from <data_source>
association [1..*] to <target_entity> as <_association> on <condition_exp>
{ <view_element>
…
@Consumption.filter.businessDate.at: true
<_association> }
Results
The @Consumption annotation added to the associated element changes how the cardinality is treated. It
specifies that the cardinality of the target data source of the associated view is set to the number of node
records that are connected to a single source record ignoring the higher cardinality due to different valid times.
In the example above OData will expose the target source cardinality of the foreign key association _assoc as
"ONE TO ONE" ([1..1]). If the temporal filter is included only one record is associated to one record of the
source data.
Entity Annotation
Context
In addition to the element annotations, which mark the boundaries of the validity period, there is an entity
annotation that enables default filtering by system date.
Procedure
…
@Consumption.filter.businessDate.at : true
define view <CdsConsumptionView>
as select from <data_source>
{ <view_element> }
● As soon as the entity uses the @consumption annotation, the fields specifying the boundaries of the valid
time must be annotated with the @Semantics annotation. Otherwise an exception will be thrown.
Results
If no query option is supplied by the OData client, this annotation automatically sets the query option as
system date. Thus, every request is filtered automatically either by the date of the given custom query option
or by the system date.
Note
Related Information
A view parameter can be filled with the value of a temporal custom query option of an OData request. To enable
this the data model needs to be equipped with an annotation to the parameter.
Prerequisites
Note
If there are discontinuances between periods, for example breaks between two subsequent periods,
the output does not contain any data. The OData request then raises the regular exception “Not found”,
as there is no data in the data set matching the request. From a semantic point of view, the entity is
considered as nonexisten at the given point in time.
● If a time period has not expired yet the end of the validity period must be set to a sufficiently large value,
preferably the largest possible value, for example December 31, 9999.
Context
A temporal parameter can be used in view modeling if the exposure of data depends on a certain condition or
calculation where the parameter is used.
To enable the value to be passed from the custom query option at=YYYYMMDD in an OData request to a view
parameter, the parameter needs an annotation. The parameter is hidden to avoid value confusion if both the
parameter and the temporal custom query option are filled with a date value.
Procedure
...
@Consumption.filter.businessDate.at : true
define view <CdsConsumptionView>
with parameters
@Semantics.businessDate.at: true
@Consumption.hidden: true
<p_at> : dats
as select from <data_source>
{ <view_element> }
where ( <validfrom> <= :<p_at>
and <validto> >= :<p_at> )
or <condition>
If the @Consumption annotation is missing on entity level and no value is supplied to the query option, an
error is thrown, as no value can be passed to the parameter.If the annotation is on entity level, the
parameter is filled with the system date.
Example
The following code example of a view is modeled to expose employees and their related information restricted
by their respective validity periods. You want to retrieve data of every employee that is employed on a specific
…
@Consumption.filter.businessDate.at : true
define view C_CurrentEmployees
with parameters
@Semantics.businessDate.at: true
@Consumption.hidden: true
p_at : dats
as select from my_employees
{ key id,
validfrom,
validto,
name,
jobtitle,
department,
found_member }
where ( validfrom <= :p_at
and validto >= :p_at )
or found_member = 1
The date value of the custom query option is passed to the parameter and is then applied in the where-clause.
All employees that are employed on the date given with the custom query option and all founding members are
exposed.
Related Information
Temporal filtering in OData requests is used to filter temporal data by a specific date. This filtering is done by a
custom query option added to the URI.
Prerequisites
● The CDS data model is annotated with the obligatory annotations to enable the retrieval of temporal data.
For more information, see Adding Annotations for Full Temporal Exposure [page 239].
For more information about annotations for a temporal parameter, see Adding Annotations when Using a
Temporal Parameter [page 243].
To filter temporal data by a specific validity date,a custom query option filled with the desired value is required.
Only the data matching the given date in the custom query option is then retrieved. If the OData client does not
supply a date in a custom query option, the system date is used as a filter reference.
Tip
Using the transaction /iwfnd/gw_client you can imitate an OData client (for example, a SAP Fiori
application) and test activated services in the SAP Gateway Client.
The following listing demonstrates the form of a URI in the SAP Gateway Client with a custom query
option:
…/sap/opu/odata/SAP/<service_name>/<EntitySet>?at=<time_data>
Procedure
● To trigger the application of temporal filtering by a specific date, add the custom query option
at=YYYYYMMDD (DATS format) with the desired validity date to the URI.
Results
The data set is filtered and retrieved by the given date in the OData request or by the system date. Temporal
filtering is applied to all requested CDS views that are equipped with the necessary annotations, including
those queried with $expand. Hence, the OData request is answered while respecting temporal filtering where
applicable.
Example
The following example illustrates how the SAP Gateway Client can be used to retrieve data with a custom
query option to filter by validity date.
URI to Retrieve Temporally Restricted Data with the SAP Gateway Client
If the underlying CDS entities use the relevant annotations, the OData request with the custom query filters the
data and exposes only employees and their respective information at the given point in time. The following
OData Output with Applied Temporal Time Travel Query Option at=20110315
Related Information
Values that are used as a filter on an element or to fill a parameter in a CDS entity can be derived from a foreign
entity. This topic explains how this functionality is modeled in CDS.
The values for parameters or filters in CDS entities are usually given by an OData client at runtime. However,
the derivation of values enables an automatic fill if no value is passed. A set of annotations triggers the passing
of values from a foreign entity (look-up entity) to the main entity. These annotations are added to the
parameter or the element in the main entity for which the value is derived.
As depicted in the figure below, the annotation set contains the navigation information to the value that is
transferred from the look-up entity to the main entity. It specifies the look-up entity's name, one of its elements
and how to single out one distinct rows where the value is taken from. The identified value is then passed back
to be used to fill a parameter in the main entity at runtime.
Related Information
The @Consumption.derivation annotations enable values to be derived from foreign entities by providing
the navigation information to those values. These values are then passed to the main entity, where they are
used at runtime.
The following list describes how the relevant @Consumption.derivation annotations are used. While only
one value is derived to fill a parameter in the main entity, one or more values can be derived to be used as a
filter in the main entity.
@Consumption.derivation.lookup Identifies the CDS entity where values are derived from.
Entity: '<lookup_entity>'
@Consumption.derivation.result Identifies the element in the look-up entity from which values are taken.
Element: '<lookup_element>'
If a filter range is derived, it identifies the element in the look-up entity that
specifies the lower limit of the range.
@Consumption.derivation.result Identifies the element in the look-up entity that specifies the upper limit of
ElementHigh: the range.
'<lookup_element>'
Note
This annotation is only used for the derivation of filter ranges.
@Consumption.derivation.bindin Singles out one or more rows in the look-up entity from which values are
g: [{…}] taken.
Binding Description
A value for a parameter can be set automatically in CDS by deriving it from another entity. This topic describes
how to annotate the parameter for which the value is derived.
Prerequisites
The annotations for the derivation of values are only applied if no value is given by the OData client. This is the
case in the following instances
● The parameter is hidden, which means it is annotated with @Consumption.hidden:true and therefore is
not available for the client
● The OData client supplies the initial value of the parameter.
Context
A parameter of a CDS entity (in the following called main entity) is usually filled with a suitable value by the
OData client. Nevertheless, there are use cases in which you want the value for the parameter to be dependent
on a value of another entity. In this case, the value for the parameter can be derived from a foreign entity,
known as a look-up entity. To do this, equip the parameter with a set of annotations that provides the
navigation information to a field in the look-up entity. The value of this field is then passed to fill the parameter
in the main entity.
Values for parameters are automatically derived from foreign entities if the parameter is hidden for the OData
Client. Otherwise, if the parameter is not hidden, the value is only derived if the OData Client supplies the initial
value of the parameter.
Procedure
● Determine the look-up entity from which the value is passed to the parameter in the main entity and add
the following annotation to this parameter:
@Consumption.derivation.lookupEntity: '<lookup_entity>'
Enter the name of the look-up entity as the value of the annotation.
@Consumption.derivation.resultElement: '<lookup_element>'
Enter the name of the element in the look-up entity as the value for the annotation.
● Determine the row in the look-up entity which matches the value that is passed to the main entity.
○ Choose a binding to identify the row in the look-up entity. It might be necessary to use more than one
binding to identify the value that is passed to the main entity.
Binding Description
targetParameter Choose a parameter binding if you want to single out a row by using a parameter
in the look-up entity.
targetElement Choose an element binding if you want to single out a row by setting a filter on an
element in the look-up entity.
#CONSTANT Choose this type if you want to fill the binding with a constant.
As the value, enter the constant you want the binding to be filled with as a literal:
'<constant>'.
#PARAMETER Choose this type if you want to fill the binding with the value of a parameter in
the main entity.
As the value, enter the name of the parameter in the main entity as a literal
'<main_param>'.
#SYSTEM_FIELD Choose this type if you want to fill the binding with a system variable.
○ Add the following annotation with the relevant binding, type and value.
The CDS view C_PurchaseOrderItems exposes information about purchase order items for a specific time
period. The end of the period is predefined as the system date. The entity has an input parameter p_start
that defines the beginning of the period. The value of this parameter can be given by the OData client. However,
if the value is not supplied, it is set automatically with the start of the current business quarter. This value is
stored in the CDS view C_BusinessQuarters and must be derived from there.
The annotations identify the look-up entity C_BusinessQuarters and the element q_beginning from which
the value is derived. The binding is applied by the parameter p-day in the look-up entity. This binding
parameter is filled with the system date because the derivation annotation in the main entity discloses the
binding type #SYSTEM_FIELD. The system date is associated with the relevant business quarter and the
beginning of this quarter is then passed to the parameter p_start in the main entity. In this scenario, the
entity exposes all purchase order items that were delivered in the current quarter until today.
The following listings display the data models for the main entity and the look-up entity.
Main Entity:
Look-Up Entity:
Related Information
A filter on an element can be set automatically in CDS by deriving it from another entity. This topic describes
how the element is annotated to filter for single values.
Prerequisites
The annotations for the filter derivations are only applied if no filter is given by the OData client. If a filter is
supplied the annotations in the CDS entity are ignored.
Context
An element of a CDS entity (in the following called main entity) can be filtered by the OData client.
Nevertheless, there are use cases, in which you want the filter to be generated automatically depending on a
value of another entity. In this case, the filter can be derived from a foreign entity,known as a look-up entity. To
It is also possible that the navigation information leads to several fields of an element in the look-up entity. In
this case all values are applied as filter criteria for the filter in the main entity.
If the OData client supplies a filter, the annotations in the CDS entity are ignored.
Procedure
● Determine the look-up entity from which the filter criteria are passed and add the following annotation to
the respective element in the main entity:
@Consumption.derivation.lookupEntity: '<lookup_entity>'
Enter the name of the look-up entity as the value of the annotation.
● Determine the element in the look-up entity from which the filter criteria are passed and add the following
annotation to the respective element in the main entity:
@Consumption.derivation.resultElement: '<lookup_element>'
Enter the name of the element in the look-up entity as the value of the annotation.
● Determine the row or rows in the look-up entity that provide the filter criteria that are passed to the main
entity.
○ Choose a binding to identify the row or rows in the look-up entity. It is possible to use more than one
binding to single out the filter criteria.
Binding Description
targetParameter Choose parameter binding if you want to single out one or more rows by using a pa
rameter in the look-up entity.
targetElement Choose element binding if you want to single out one or more rows by setting a filter
on an element.
#CONSTANT Choose this type if you want to fill the binding with a constant.
As the value, enter the constant, you want the binding to be filled with as literal:
'<constant>'.
#PARAMETER Choose this type if you want to fill the binding with the value of a parameter in the
main entity.
As the value, enter the name of the parameter in the main entity as literal
'<main_param>'.
#SYSTEM_FIELD Choose this type if you want to fill the binding with a system variable.
○ Add the following annotation with the relevant binding, type and value.
Example
The CDS entity C_SalesOrdersCountries exposes information about sales orders with buyers from a
certain country. The relevant country is given by the OData client in the input parameter p_country. A filter is
applied to the element that provides the information about the buyers. Only those sales orders are retrieved
that list buyers from the given country.
The values for the filter on the element buyer in the main entity are derived from the look-up entity
C_BusinessPartners. In this entity, it is the element id, from which the values for the filter are taken. The
binding is applied by a filter on the element country with the filter criteria given by the input parameter of the
main entity p_country. The buyers in those rows that were singled out are then passed to the main entity and
function as a filter for the element buyer. This means that only those buyers that match the country criterion
are passed to the main entity as filter criteria for the sales orders.
If the parameter p_country is supplied with 'Germany' by the OData client, only the sales orders with buyers
located in Germany are retrieved.
The following listings display the data models for the main entity and the look-up entity.
Main Entity:
Related Information
A filter on an element can be set automatically in CDS by deriving it from another entity. This topic describes
how to annotate the element to filter for a range of values.
Prerequisites
The annotations for the filter derivations are only applied if no filter is given by the OData client. If a filter is
supplied the annotations in the CDS entity are ignored.
Elements of CDS entities (in the following called main entity) can be filtered by a range of values if you want to
retrieve all entries for values that fall into a certain range. If you want this filter to be generated automatically
depending on a range of values from a foreign entity, known as a look-up entity, you can derive the values for
the filter range. To do this, equip the element in the main entity with a set of annotations. These annotations
provide the navigation information to the fields in the look-up entity with the range limits. The values of these
fields are then passed to the main entity to be used as filter criteria on the element.
It is possible that the navigation information leads to several ranges in the look-up entity. In this case all ranges
are applied as filter criteria for the filter in the main entity.
If the OData client supplies a filter, the annotations in the CDS entity are ignored.
Procedure
● Determine the look-up entity from which the filter criteria are passed and add the following annotation to
the respective element in the main entity:
@Consumption.derivation.lookupEntity: '<lookup_entity>'
Enter the name of the look-up entity as the value of the annotation.
● Determine the elements in the look-up entity that specify the lower limit and the upper limit of the range
and add the following annotations to the respective element:
@Consumption.derivation.resultElement: '<lower_limit>'
@Consumption.derivation.resultElementHigh: '<upper_limit>'
As the value of these annotations, enter the name of the elements that specify the lower limit and the
upper limit in the look-up entity.
● Determine the row or rows in the look-up entity that provide the filter criteria that are passed to the main
entity.
○ Choose a binding to identify the row or rows in the look-up entity. It is possible to use more than one
binding to single out the filter criteria.
Binding Description
targetParameter Choose parameter binding if you want to single out one or more rows by using a pa
rameter in the look-up entity.
targetElement Choose element binding if you want to single out one or more rows by setting a filter
on an element.
#CONSTANT Choose this type if you want to fill the binding with a constant.
As the value, enter the constant, you want the binding to be filled with as a literal:
'<constant>'.
#PARAMETER Choose this type if you want to fill the binding with the value of a parameter in the
main entity.
As the value, enter the name of the parameter in the main entity as a literal
'<main_param>'.
#SYSTEM_FIELD Choose this type if you want to fill the binding with a system variable.
○ Add the following annotation with the relevant binding, type and value.
Example
The CDS entity C_SalesOrderQuarterly exposes information about sales orders for a specific business
quarter. The relevant business quarter is given by the OData client in the input parameter p_quarter in the
main entity. A filter is applied to the element that provides the information about the sales order date to
retrieve only those sales orders that fall into the given business quarter.
The sales order dates are filtered for a specific business quarter. The limits for the selected business quarter
are derived from the look-up entity C_BusinessQuarters. In this entity, it is the element q_beginning that
defines the lower limit and the element q_end that defines the upper limit of the business quarter.
The business quarter is determined by the input parameter p_quarter, which singles out one row. The limits
of the given business quarter are taken from this row according to the elements that are specified by the
annotation. The sales order dates are compared with these two values; and only those sales orders whose
dates match the limits are retrieved.
The following listings display the data models for the main entity and the look-up entity.
Main Entity:
Look-Up Entity:
The descriptions in this topic refer to the range of functions for text and fuzzy searches that are provided in the
context of SAP HANA.
The full text searching (or just text search) provides you with the capability to identify naturallanguage terms
that satisfy a query and, optionally, to sort them by relevance (ranking) to the query. The most common type of
search is to find texts that contain the term specified and return them in the order of their similarity to these
terms.
Fuzzy search is a fast and fault-tolerant search feature of SAP HANA. The basic concept behind the fault-
tolerant search is that a database query returns records even if the search term (user input) contains
Within the context of the ABAP programming model for SAP Fiori, you only need to enable the text and fuzzy
search functionality in your data model definitions. For this purpose, you implement it in designated CDS views
using appropriate text and fuzzy search annotations (listed below).
Note
As an application developer however, you must ensure that your CDS views are suitable for text and fuzzy
search enabling. For more information take a look at the corresponding topics in the SAP HANA Developer
Guide.
As the name suggests, search annotations enable the search feature on the CDS view elements.
First of all, you need the following CDS annotation at the view level:
@Search.searchable: true/ Defines whether a CDS view is generally relevant for search scenarios. This anno
false tation provides a general switch and a means to quickly detect whether a view is
search-relevant or not. Set to value true in order to enable search support by
means of @Search annotations. Here, at least one view field must be defined as
@defaultSearchElement at element level.
All view elements that are annotated for the default search define the search
scope. (The search will be performed on all elements that have this annotation.).
Caution
Such a search must not operate on all elements – for performance reasons
and because not all elements qualify for this kind of access.
@Search.fuzzinessThreshold This annotation specifies the least level of fuzziness the element has to have in
: <value> order to be considered in a fuzzy search at all.
The <value> defines the threshold for a fuzzy search (how fuzzy scores are cal
culated when comparing two strings or two terms).
Possible values are: 0..1 The default value is 1. The fuzzy search algorithm cal
culates a fuzzy score for each string comparison. The higher the score, the more
similar the strings are. A score of 1.0 means the strings are identical. A score of
0.0 means the strings have nothing in common.
@Search.ranking: <value> This annotation specifies how relevant the values of an element (view field) are
for ranking, should the freestyle search terms match the element’s value.
● HIGH - The element is of high relevance; typically, this is useful for IDs and
their descriptions.
● MEDIUM - The element is of medium relevance; designated usually for im
portant elements.
● LOW - Although the element is relevant for a freestyle search, a hit for this el
ement has no real significance for the ranking of a result item.
Tip
For the fuzzy search threshold, we recommend using the default value 0.7 to start with. Later on, you can
fine-tune the value based on your experiences with the search. You can also fine-tune the search using
feedback collected from your users.
Example
The listing below implements a search model for searching products. The model definition results from a join
between two data sources that already specify the persistence layer for searching: both database tables are
The annotation @Search.searchable: true marks the view as searchable. In addition, the elements Name
and Category are annotated with @Search.defaultSearchElement: true. This means that a freestyle
search is enabled on the search UI where it is possible to search for the annotated elements. The annotation
@Search.fuzzinessThreshold: 0.7 (0.8) defines that the text search should be applied to the element
Category with a similarity value of 70% and to the element Name with a similarity value of 80%.
...
@Search.searchable : true
@Search.defaultSearchElement : false
ProductDescription.language as Language,
@Search.defaultSearchElement : true
@Search.fuzzinessThreshold : 0.8
@Search.ranking : #HIGH
ProductDescription.text as Name,
@Search.defaultSearchElement : true
@Search.fuzzinessThreshold : 0.7
@Search.ranking : #LOW
Product.category as Category
}
Preview:
Standard filter allows to search for product category and product name
This topic explains how you can provide aggregate data for your SAP Fiori application. The available aggregate
functions operations are sum, minimum, maximum, and average. Alongside this, the framework also provides
options for counting.
We speak of aggregate data when numerical values are combined to form a single value that signifies meaning.
General assumptions can be drawn from this value that is representative for all values that were included in the
calculation of the value.
● sum
● minimum
● maximum
● average
These functions determine a value from which you can assume information relating to all the values that were
included in the calculation.
Apart from these functions, the following counting functions are also available:
● count
● distinct count.
These counting options determine a natural number based on the number of entries in the calculation.
Aggregate data calculated by the SADL framework provides additional and enhanced information for your list
reporting app.
To display aggregate data in your application, annotate the respective elements in CDS with the annotations
described in Annotating Aggregate Functions in CDS [page 264]. These annotations cause the CDS entity to be
respected as an aggregated entity by OData. A thorough description of how OData interprets the annotations is
provided in OData Interpretation of Aggregation Annotations [page 267].
The elements for which you want to display aggregate data in your SAP Fiori App must be annotated in the CDS
entity with the relevant annotation for the aggregate function.
The annotation @Aggregation.Default: #<AGGR_FUNCTION> enables the aggregation of the values of the
annotated element.
Only measures can be annotated with an aggregation annotation. Measures are elements that either represent
numerical values, which means they can be summed, averaged, or otherwise mathematically manipulated. In
addition, elements with date values, can also be compared with each other to determine the maximum or
minimum. Date values can also be measures. Typically, measures are units that express the size, amount, or
degree of something, for example prices.
The other elements in a CDS entity are called dimensions. Dimensions provide structured labeling information
about otherwise unordered numeric measures. They are relevant for the grouping and the order of the
elements in the Fiori App.
The SADL framework supports the following aggregating functions for measures:
@Aggregation.Default: #SUM Calculates the sum of the values of the annotated element.
@Aggregation.Default: #MAX Calculates the maximum of the values of the annotated element.
@Aggregation.Default: #MIN Calculates the minimum of the values of the annotated element.
@Aggregation.Default: #AVG Calculates the average of the values of the annotated element.
Note
The value of the annotated element is always displayed as 1 for
single data records, regardless of the actual value of the ele
ment. Only when an aggregated value is requested is the count
value displayed.
Only one aggregate function can be used on one element. You cannot display different aggregated values of the
same element.
Apart from the annotations that trigger the aggregation of measure values, it is vital to use an annotation that
defines the properties that must always be selected in the OData request. In our analytical operations case, the
elements that must always be selected are the technical keys. This means that, even if the columns of the
technical keys are not selected by the UI, the OData request selects the technical keys to avoid grouping.
For more information on grouping, see OData Interpretation of Aggregation Annotations [page 267].
If the UI requests group records, the technical keys do not need to be selected since grouping is desired.
The following annotation must be used on entity level to specify the key(s). The annotation ensures that the
technical keys are selected when needed, even if the columns with the technical keys are not selected by the UI.
@UI.presentationVariant: Defines the properties that must always be included in the result of
[{requestAtLeast: the queried collection if no grouping is desired.
['<TECHNICAL_KEY>']}]
Example
The following listing displays a CDS entity in which all the necessary annotations for analytical operations are
used. This view describes sales order combined with associated product and customer information.
Note
The aggregate functions only respect values with the same semantics. This means, that, if you have prices
in different currencies that are annotated with an aggregation annotation, you receive aggregated data for
each currency.
The following figure displays the maximum tax amount with regard to the respective currency.
Related Information
The following sections provide an overview of the most prominent features of aggregated entities in OData.
Data models with aggregation annotations are considered as aggregated entities by OData. The behavior of
these aggregated OData entities differs from non-aggregated entities.
OData Annotations
The OData entity is given multiple annotations based on the aggregate annotation you use in CDS for your data
model. The following figure displays the metadata of an aggregated entity that processes sales order items.
In the example of the screenshot above, this OData annotation can be found in the first line of the extract of the
metadata.
Measures
The aggregated entity is characterized by measures and dimensions. Measures are those properties that are
annotated with the annotation relevant for aggregating data in CDS. Measures are given the OData annotation
sap:aggregation-role=”measure”.
In the example of the screenshot above, there are six properties which are marked as measures:
ConvertedGrossAmount, GrossAmount, NetAmount, TaxAmount, AllItems, and DistinctProducts.
Dimensions
Dimensions are all properties that are neither marked as measures nor as attributes. Dimensions are given the
OData annotation sap:aggregation-role=”dimension”.
In the example of the screenshot above, there are six OData properties which are marked as dimensions:
SalesOrderID, ItemPosition, Customer ID, Product, CurrencyCode, and TargetCurrency.
Each dimension can have a maximum of one text property. A text property is an element that is defined as a
text element in CDS, as described in Defining Text Elements [page 271]. Dimensions with a text property are
annotated by OData with sap:text="<TEXT_PROPERTY>".
Attributes
Dimensions can have attributes. Attributes are elements that are annotated with the annotation
@Consumption.groupWithElement: 'ElementRef'. The attributes are always considered as an addition
to their corresponding dimension. Attributes are annotated by OData with sap:attribute-
for="<DIMENSION>".
In the example of the screenshot above, the dimension CustomerID has the attribute CompanyName and the
dimension Product has the attribute ProductCategory.
In the example of the screenshot above, the property for the generated ID can be found as the first property on
the list.
The ID is also generated for every group record when it is requested for the first time. Following from this, you
can use this ID in a further request.
Example
This behavior is exemplified by a request on the entity that supplies the metadata above. It retrieves sales
order items. The following request selects the generated ID ( ID), the dimension Product, and some
aggregated measures related to the selected dimension.
.../sap/opu/odata/SAP/<service_name>/ZDEMO_C_SOI_ANLY?
$select=ID,Product,GrossAmount,NetAmount,TaxAmount,AllProducts
Results of requesting data from aggregated entities depend on the elements you select in your OData request.
Grouping and aggregation are both driven by the elements you request with the parameter $select in entity
set queries. The result of a query consists of aggregated entities with distinct values for the requested
dimension properties and requested measures are aggregated using the aggregate function with which the
measure elements are annotated in CDS.
If an attribute is requested, the result is grouped by its corresponding dimension and within that group it is
grouped by the attribute itself.
Note
If you use a SAP Fiori app, the $select statement of the OData request directly depends on the columns
you select in the list reporting app. The following descriptions of requesting data with OData can also be
managed by selecting the respective columns in your Fiori App.
If all primary key elements of the requested CDS entity are included in the query option $select, no grouping
is possible since every record is unique. Hence, an OData request with all key elements behaves just like a non-
aggregated entity. Consequently, no aggregate data is calculated.
If not all key elements are included in the OData request, the requested dimensions are grouped and the
requested measures are aggregated according to their annotated aggregate function. For every distinct
combination of dimension values (after evaluating $filter), the result includes an aggregated entity with
aggregated values for the requested measures.
Note
Each group record is given its own generated ID, which can be reused in requests to retrieve the same
results.
Only if no dimension and no attribute are requested does the result show the aggregate data of measures for
the whole entity set.
You can still execute other query options, such as $filter or $orderby on grouped requests. The filtering is
executed before the grouping, so that the groups are created from the available records after the filtering. The
ordering is executed after the grouping, which means the records within a group are ordered according to the
query option.
You can filter for properties that you do not select, but you cannot order by properties that are not included
in the $select due to the order of executing query options mentioned above.
Example
Assume you have an aggregated entity of sales order items and you group them by product. From this
group record, you can navigate directly to the associated entity of products if the association exists in CDS.
The same holds true for the query option $expand. Only properties that are selected can be expanded.
Note
The target entity of the navigation or the expand is also given an aggregated ID if the underlying data model
is also aggregated.
Related Information
This section describes how to determine and provide texts for a CDS view element within the context of the
SAP Fiori programming model.
Contents
Within the context of CDS views, the text elements establish the link between identifier elements (code values)
of the view and its descriptive language-independent texts. For example, you can define a link between a
company code and the (descriptive) company name, or between currency code and the currency name. These
kinds of descriptive texts are language-independent.
Relevant Annotation
Annotation Effect
Note
The usage of this annotation excludes the usage of
@ObjectModel.text.association.
Note
SADL Runtime Behavior: In OData exposure scenarios, the first text element listed in the annotation array
will be handled as a descriptive text of the annotated field.
Example
In the listing below, the CDS view I_Plant defines the fields PlantName and PlantDescription that both
serve as language-independent descriptions for the view field Plant.
...
define view I_Plant as ...
{
@ObjectModel.text.element: ['PlantName','PlantDescription']
key Plant,
PlantName,
PlantDescription,
...
}
Caution
Obsolete Use: You may be aware that the Consumption.labelElement annotation is used in the same
context. This annotation also enables consumers to identify through which elements the descriptive texts
for the identifier elements can be retrieved. In the example below, the label of currency is set through the
CurrencyText field:
Using the CDS text association, you can define the relationship between an element (field) and its
corresponding texts or descriptions. The texts are usually language-dependent and are displayed in the end
user's language. If you annotate an element with a text association (as described below), the associated text or
description field is added as a field to the referencing entity. At runtime, this field is read from the database and
filtered by the logon language of the OData consumer automatically. It is not necessary to use session
properties or view parameters in your CDS view.
Steps
1. Create a data definition with a CDS view that serves as text provider
The following set of CDS annotations is relevant when defining text views:
Relevant Annotations:
The following annotation is required at the view level:
@ObjectModel.dataCategory Indicates that the annotated CDS view represents texts (defines a text pro
: #TEXT vider view)
Note
Usually one key element is used to specify the language!
The following annotations are required at the view element level to annotate the language key element and
the text elements from the view’s element list:
@Semantics.text: true Identifies view elements as text elements (fields pointing to a textual descrip
tion)
Note
In general, you can annotate more than one view field as a text field. How
ever, only the first annotated field will be considered in the text consumer
view for OData exposure.
More on this:
○ ObjectModel Annotations [page 428]
○ Semantics Annotations [page 445]
Example
The listing below implements a sample text view. Its entity is named I_UnitOfMeasureText and uses
database table T006A as its data source. In this example, the two fields MSEHT (UnitName) and MSEHL
(UnitLongName) are annotated as text fields with @Semantics.text: true. However, note that - in
OData exposure scenarios - the first text element listed in the annotation array will be handled as a
descriptive text of the annotated field in the consumer view.
...
@ObjectModel.dataCategory: #TEXT
2. Create a text association from your consumer CDS view to the text provider view
The following CDS annotation is relevant when creating text associations:
@ObjectModel.text.associa Name of an association with a text view that provides descriptive texts for the
tion: annotated element. In other words: the annotation indicates that the descrip
'<_AssocToTextProvider>' tion for the annotated element is available using the text association
<_AssocToTextProvider>.
More on this:
○ ObjectModel Annotations [page 428]
Example
...
Caution
If you use the Referenced Data Source (RDS) option for OData service creation, it is important that you
always regenerate your gateway project in transaction SEGW after you add, change, or remove text
associations in the consumer views contained in the project. The same is true if you change the order of
fields in the text provider view - since such changes trigger the data type change of the entity set in gateway
project.
The implementation of a value help in CDS enables the end user to choose values from a predefined list for
input fields on a user interface.
You can define value helps in the CDS data layer for any input field on the UI (for example, selection fields,
parameters, or writable fields in transactional scenarios) . A value help is useful when the values for the input
field have to be taken from a predefined set of values. When you call the value help, it displays all the available
values from the value help provider. It appears on the UI when you choose the button in the input field or
press the F4 key. The end user can filter by related information to identify the correct value. This makes it
easier to find the desired value, especially if the value itself contains little or no identifying information, for
example, an ID number.
Example
To help the end user to enter the right customer ID to create a new booking, the application developer
defines a value help that enables the user to enter the name or any other element from the value help
Expand the following figure to view the procedure of calling the value help on a Fiori Elements UI.
For the default implementation of the value help, you can use any CDS entity that contains the desired values of
the element for the input field. You do not need to explicitly define a CDS entity as the value help provider.
However, the value help provider must be exposed for the OData service to make use of the value help.
Note
Any annotation that is maintained in the value help provider is evaluated. This means that associated
entities, value helps, and text associations of the value help provider view are also displayed and can be
used in the value help. This means that you can have a value help in the value help.
The following value help options are available within the programming model:
Related Information
A simple value help is convenient if you want to display values from the value help provider for an input field.
Context
You want to provide a value help for an input field on the UI.
The following steps implement a value help for a customer ID field, using a booking CDS view as an example.
Procedure
1. Create a data definition for a CDS view that serves as a value help provider. It must contain a field with the
available values for the input field in the source view.
Example
The value help provider view contains the customer ID and fields to identify the customer ID, such as
the customer's name or address. The end user can then filter by these fields to find the right customer
ID.
2. In your CDS source view, add the following annotation to the element for which you want to provide the
value help on the UI.
The annotation defines the binding for the value help to the value help providing entity. You must specify
the entity name and the element providing the possible values for the annotated element.
Example
The following code example shows how an annotation is used on the element CustomerID in /DMO/
I_Booking. It references the value help provider view (/DMO/I_CUSTOMER_VH) for the customer ID
and the element providing the possible values (customer_id) in the value help provider view.
Results
Choosing F4 in the selection field opens a search mask and the end user can filter by any field in the value help
provider view. Selecting an entry transfers the value of the element that is referenced in the annotation to the
annotated element in the source view.
The metadata of the OData service displays the value help implementation for the following properties:
● The property in the CDS source view for which a value help is implemented (sap:value-
list="standard")
● The value help provider entity type (sap:value-list="true")
● The value help provider entity is marked as Target in the Annotations property. The value list
enumerates every property in the value help provider that is exposed for the value help (Annotation
Term="Common.ValueList").
● The element that is defined in the mapping condition is marked as an inbound and outbound parameter
Record Type="Common.ValueListParameterInOut".
Expand to see the extracts of the metadata document of a service exposing a booking CDS view and the value
help provider for the element CustomerID.
Postrequisites
If the source view is exposed for an OData service, you need to include the value help provider view in the
service to be able to retrieve the values from the value help.
● Associations: If the target of the association is included in the OData service, the elements of entities
associated with the value help provider are also displayed as additional input fields.
● Search Capabilities: Including search capabilities in your value help provider enables the end user to
search for any detail in an input field.
● Value Helps: The value help can itself contain value helps.
● Text: Text that is provided for the value help provider is also displayed.
For dropdown value lists, the OData $metadata document includes the annotation sap:value-list=
"fixed-values" instead of standard on the property in the source view for which the value help is
implemented.
The UI displays the possible values for the input field in a dropdown list. The following image shows a value help
list for the carrier ID field in the booking scenario.
Example
The following code example shows how the annotation is used on the element CustomerID in /DMO/
I_Booking. It references the association to the value help provider view (_Customer).
Context
It is possible to provide more than one value help on one element. The end user selects which value help to use
to find the correct value.
The following image displays the value helps for the carrier ID element in the booking CDS view. One value help
provider is defined by a carrier CDS view and one by a connection CDS view that also contains the carrier ID
field.
Procedure
1. To implement two value helps on one element, proceed as described in Simple Value Help [page 277] and
add another entity as a value help provider.
You can define more than two value helps on one element.
2. Assign labels to the different value helps to differentiate them on the UI.
If you have more than one value help, it is important that all except one are equipped with a qualifier. The
default value help is the one without a qualifier. The qualifier marks the value helps that are less important.
If all value helps are annotated with the qualifier argument, then none of them are displayed as there is no
default.
Results
Choosing F4 in the input field opens a search mask with the fields of the default value help. The default value
help is the one without a qualifier. The end user can select which value help to use from a dropdown menu.
A preset filter condition can be established by an additional binding for the value help.
Context
You use an additional binding to define more than one binding condition between the source view and the value
help provider. The value help is then automatically filtered by the additional binding. It proposes only entries
that match the additional binding. This additional binding can either be another element or a parameter. These
need to be present in the source view and in the value help provider view. When an entry is selected in the value
help provider, the values of both binding elements are transferred to the input fields of the source CDS view.
In our booking scenario, we can apply the value help with an additional binding on the field ConnectionID.
The value help provider is a view that manages connections. This value help provider contains not only the
field for the connection IDs, but also a field for carrier IDs, which is also in the consumer view. We can
establish a second binding condition so that the value help provider only displays connections with the
prechosen carrier ID.
Procedure
1. Create a data definition for a CDS view that serves as a value help provider. It must contain a field with the
available values for the input field in the source view. In addition, it must contain the field for which the
additional binding is established.
The value help provider view contains the connection ID and the carrier ID, for which a mapping condition
is defined.
2. In your CDS source view, add the following annotation to the element for which you want to provide the
value help on the UI.
The additional binding defines a second condition for the value help on the same target value help provider
entity for filtering the value help result list and/or returning values from the selected value help record. The
additional binding can be defined for an additional element or parameter.
Results
Choosing F4 in the selection field opens a search mask and the end user can display all available entries in the
value help provider or filter by a field, for example, the destination airport. If the carrier ID is already filled in the
consumer view, the value help provider is prefiltered by that value. Selecting an entry in the value help transfers
the connection ID as well the carrier ID to the CDS consumer view.
The metadata of the OData service displays the value help implementation on the following properties:
● The property in the CDS source view for which a value help is implemented (sap:value-
list="standard")
● The value help provider entity type (sap:value-list="true")
● The value help provider entity is marked as Target in the Annotations property. The value list
enumerates every property in the value help provider that is exposed for the value help (Annotation
Term="Common.ValueList").
● The elements that are defined in the mapping conditions are marked as inbound and outbound parameters
Record Type="Common.ValueListParameterInOut".
Next Steps
If the consumer view is exposed for an OData service, you need to include the value help provider view in the
service to be able to retrieve the value help.
Relevant Annotations
Annotation Effect
@EndUserText.label: This annotation is used to define translatable semantic short texts (with maxi
'<text>' mum 60 characters) for an element of the CDS view (label text).
@EndUserText.quickInfo: The annotation defines a human-readable <text> that provides additional infor
'<text>' mation compared to the label text. The quick info is used for accessibility hints or
the mouse over function.
Remember
The <text> specified in the source code should consist of text in the original language of the CDS source
code and will be translated into the required languages.
Example
The listing below demonstrates the usage of @EndUserText annotation at the view and element (field) level:
...
@EndUserText.label: 'List with Sales Orders' -- Annotation at the view level
Tip
Press F1 in the CDS source code editor for extended help content on @EndUserText annotation!
Motivation
When creating data models for business objects, database tables are often used as a data source for the CDS
views that define the business object’s data model.
In such cases, it may also happen that existing legacy tables (which originate from older releases) are to be
reused in the definition of the new data model. Tables like these may sometimes contain quite short or cryptic
field names. On the other hand, when describing the data model using CDS, you should try to use semantically
descriptive names.
Example
In the following example, the table field names bpartner and ostatus are mapped to the alias names
Customer and FinalStatus.
...
@ObjectModel.foreignKey.association: '_BusinessPartner'
bpartner as Customer,
...
@ObjectModel.foreignKey.association: '_Status'
ostatus as FinalStatus,
...
Whenever the table field names and the corresponding element names in the CDS view do not match (except
for camel-case differences), this causes problems when activating the CDS view. As shown in the following
figure, these problems are only noted as a warning at design time.
At runtime, however, a mapping problem like this would cause the relevant fields to be unable to write records
to the active business object’s instances.
Solution
One such problem can be solved in quite a simple way by using a classic database view for mappings between
table fields and the element names of the CDs view and by using this database view for writing/storing the
active data.
Steps in Detail
1. Start the transaction SE11 and create a classic database view for mapping table fields onto the
corresponding elements of the CDS view.
@ObjectModel: {
transactionalProcessingEnabled: true,
...
writeActivePersistence: '<database_view>',
...
}
A draft-enabled association retrieves active data, if you follow the association from the active source instance,
and draft data, if you follow it from the draft source instance. An association that is not draft-enabled always
retrieves active data even if the source entity is a draft instance.
Associations are used to navigate from a source entity of a business object to a related target entity. If the
target entity is draft-enabled, there might be two versions of data: active data and draft data. Associations that
are not draft-enabled always return the active data of the target entity, regardless of the draft status of the
source entity. On the other hand, draft-enabled associations always return the version of data that matches the
draft status of the source entity.
In many cases, associations are draft-enabled by default as there is a composition or another close relationship
between source and target entity.
The association types that are presented in the following list and in the figure below are automatically draft-
enabled. Every other association is not draft-enabled and must be annotated with the relevant information to
enable draft capabilities.
Note
● Association between two nodes that have the same root node instance
Example: Association from Schedule Line (CHILD of CHILD) to another Schedule Line (CHILD of CHILD)
that belongs to the same Sales Order (ROOT) or
Association from Sales Order Item (CHILD) to another Sales Order Item (CHILD)
The following image illustrates the associations that are draft-enabled by default. The scenario that is used is a
business object with a sales order root, sales order items, and schedule lines.
Apart from the association types listed above, all other associations are not draft-enabled automatically. They
need to be annotated to draft-enable them. The procedure differs depending on the association cardinalities.
Associations that are not draft-enabled by default can be annotated to enable them with draft capabilities. This
topic explains which annotations are used for associations with cardinality to-one and why they are needed.
Context
A list of automatically draft-enabled associations is provided here: Associations that are Draft-Enabled by
Default [page 288]
All other associations must be annotated to draft-enable them. The most frequent use case among those
associations that need annotations to draft-enable them is:
● Associations between two nodes of the same business object (BO) that neither have the same parent nor
the same root node instance.
Example
An association from a sales order item of sales order A to a sales order item of sales order B.
As the items belong to different sales orders, their root node instance is different. However, they are
part of the same BO.
Prerequisites
● Both, the source entity and the target entity are draft-enabled. Draft-enabled entities have the CDS
annotations specific to transactional processing and the CDS annotations specific to draft enablement.
More on this: CDS Annotations Specific to Transactional Processing [page 114] and CDS Annotations
Specific to Draft Enablement [page 115]
● The join condition uses the primary key of the target entity.
● The association cardinality is [0..1]. This means that a maximum of one target entity is associated with
one source entity.
For associations with other cardinalites, check Draft-Enabling for Reverse Associations [page 294].
Relevant Annotations
To enable an association with draft capabilities, use the following @ObjectModel annotation on the
association:
@ObjectModel.association.draft.Enabled: true
_Assoc
Note
In UUID-based scenarios, draft data is automatically given a unique key as the UUID field (which is derived
from the active table) is filled with a new UUID for every draft data record. As the join condition uses the
primary key of the target entity (in this case the UUID field), the navigation to the draft data can use the
same fields as the navigation between the active instances of the entity.
In contrast to the UUID scenario, the semantic key is not unique for draft data as multiple draft entries might
have the same key. For this reason, a new field (DRAFTUUID) is generated in the draft table to serve as a unique
key field for draft entities. The UUID of the associated entity is then used for the join condition of the
association and stored in an additional field in the draft source entity. This field, named <prefix>DRAFTUUID,
is also generated automatically and is given a prefix that needs to be defined in an annotation. A prefix is
necessary here to avoid a dublicate of the field DRAFTUUID in the source entity, in which the entity's own UUID
is stored.
To determine the prefix, the following @ObjectModel annotation must be used on the association in the CDS
view of the source entity in addition to the annotation mentioned above:
@ObjectModel.association.draft.fieldNamePrefix: 'prefix'
_Assoc
In this way, the join condition between active entities, for which semantic keys are used, can be translated for
the association between entities in draft versions, using the new draft UUID key of the target entity in the join
condition.
Example
An association between instances of the same business object that do not have the same root node instance
exemplifies this scenario. The business object in our case manages employee data; in particular the
responsible manager for the respective employee. The reduced data model for this semantic key scenario is
the following:
Entity Element
first_name
last_name
manager_empl_id
Employees are listed with their names and an ID and their manager.
An association from an employee to their manager is an association that is not draft-enabled by default and
fulfills the requirements to draft-enable it:
The following code example shows the CDS data definition for the BO-view of the employee with the relevant
annotations to draft-enable the association. In this example the BO uses semantic key and therefore the
association must be annotated with both annotations explained above.
@AbapCatalog.sqlViewName: 'I_EMPL'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'BO-view employees'
@ObjectModel: {
transactionalProcessingEnabled: true,
compositionRoot: true,
createEnabled: true,
deleteEnabled: true,
updateEnabled: true,
writeActivePersistence: 'db_empl',
semanticKey: ['empl_id'],
draftEnabled: true,
writeDraftPersistence: 'db_empl_d',
}
define view I_empl_tp_d
as select from db_empl
association [0..1] to I_empl_tp_d as _manager on $projection.manager_empl_id =
_manager.empl_id
{
key empl_id,
first_name,
last_name,
manager_empl_id,
@ObjectModel.association.draft.enabled: true
@ObjectModel.association.draft.fieldNamePrefix: 'manager'
_manager
}
The following figure illustrates the table header of the draft table db_empl_d (in our example) with the
generated fields.
Related Information
Associations that are not draft-enabled by default can be annotated to enable them with draft capabilities. This
topic explains which annotations are used for associations that are defined in the reverse direction of another
association.
Context
The following topic describes how reverse associations are draft-enabled if they are not draft-enabled by
default.
Note
A reverse association is an association that connects two nodes for which an association in the other
direction already exists. The source and the target entity are exchanged but the join condition uses exactly
the same elements. This means that reverse associations do not necessarily use the primary key of the
target entity in the join condition.
Use cases for defining reverse associations are associations that do not meet the prerequisites for draft-
enabling them as described in the topic Draft-Enabling for Associations with Cardinality To-One [page 291].
These are:
● Associations that do not use the primary key of the target source entity in the join condition.
● Associations with cardinality to-many.
These associations can be defined as reverse associations using an annotation. In this way, the navigation
information of their counterparts can be used for these associations as well. This is crucial when semantic keys
are used.
Prerequisites
● Both the source entity and the target entity must be draft-enabled. Draft-enabled entities must have the
CDS annotations specific to transactional processing and the CDS annotations specific to draft
enablement.
More on this: CDS Annotations Specific to Transactional Processing [page 114] and CDS Annotations
Specific to Draft Enablement [page 115]
● The association is a reverse association of a draft-enabled association with cardinality to-one.
To explicitly enable an association with draft capabilities, use the following @ObjectModel annotation on the
association:
@ObjectModel.association.draft.Enabled: true
_Assoc
This annotation ensures that for the defined association _Assoc, the association path leads to active data if
the source entity is active and to draft data if the source entity is a draft instance.
To mark the association as a reverse association, add the following @ObjectModel annotation to the
association:
@ObjectModel.association.reverseAssociation: 'Inverse_Assoc'
_Assoc
For the value, specify the alias of the association to which the association _Assoc is a reverse association. This
annotation enables the association to use the same join condition for draft instances as its counterpart (for
example field prefixes in scenarios with semantic keys). In the same way the correct navigation is ensured
when following an association with cardinality to-many.
Example
We consider the same example scenario as in the topic: Draft-Enabling for Associations with Cardinality To-One
[page 291]: an association between instances of the same business object. From one employee instance we
want to be able to navigate to the employee's manager and in the other direction we want to get all the
managed employees of one manager.
The association from manager to employees is the reverse association to the association from one employee to
their manager, which has cardinality to one. We take for granted that this association is draft-enabled, which
means, it is annotated with the relevant annotations, as it is done in the previous topic.
The reverse association, however, is [1..*] as one manager can manage multiple employees. The relevant
annotations for draft-enabling this association are the subject of this example. The association must be
annotated with @ObjectModel.association.draftEnabled: true and
@ObjectModel.association.reverseAssociation:'Inverse_Assoc'.
The following code example shows the CDS data definition for the business partner BO view with the relevant
annotations for draft-enabling this association.
@AbapCatalog.sqlViewName: 'I_EMPL'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'BO-View employees'
@ObjectModel: {
transactionalProcessingEnabled: true,
compositionRoot: true,
createEnabled: true,
deleteEnabled: true,
updateEnabled: true,
writeActivePersistence: 'db_empl',
semanticKey: ['empl_id'],
The association _employees is labeled as reverse association for the association _manager. It adopts all the
necessary features of its counterpart.
Related Information
Metadata-driven UIs are dynamic UIs because metadata, namely CDS annotations in this context, are stored in
a repository and can be retrieved from the client as needed. CDS annotations depend on the UI in which they
are supposed to be used.
UIs might differ from user to user. Even though if, for example, three different users use the same application,
each of them might have different permissions or different preferences, which results in different UI
perspectives. Users might want to personalize their UIs and see different columns in tables, for example. CDS
annotations offer default views for modelling UIs, however, CDS annotations can be overruled by
personalization preferences.
The following chapters inform you about CDS annotations that you can use to define metadata-driven UIs, and
answer the following questions:
Get an overview of how to use UI annotations for lists and tables for SAP Fiori UIs.
In Fiori we distinguish tables and list. Both mostly hold homogeneous data, but lists hold in general rather
simple data whereas tables hold usually more complex ones.
Lists are mostly used in the master list section of the master-detail floorplan and in popovers or dialogs. Sure
there is also the possibility to have them in full-screen floorplans for certain use cases.
A table contains a set of line items and usually comprises rows (one row showing one line item) and columns.
Line items can contain data of any kind, but also interactive controls, for example, for editing the data,
navigating, or triggering actions relating to the line item.
To display large amounts of data in tabular form, several table controls are provided. These are divided into two
groups, each of which is defined by a consistent feature set:
In order to expose a CDS view in a table-like or list-like format, you can use the annotations explained in the
following sections:.
Get information about what UI annotations to use to work with titles of lists or tables for SAP Fiori UIs.
You can use the following UI annotation to define what can be displayed in the title of a table or a list:
Sample Code
...
@UI.headerInfo: { typeNamePlural: 'Sales Orders' }
define view ZExample_SalesOrder as select from sepm_cds_sales_order as so {
...
}
8.12.1.2 Columns
Get information about what UI annotations to use to work with columns of lists or tables for SAP Fiori UIs.
What columns are needed for a table or list depends on the use case, for example, an overview table may
require more fields than a value help list. For this reason, you can define several list layouts and table layouts
that are distinguished by a qualifier, for example 'ValueList'.
If a CDS view contains analytical annotations, for example the @DefaultAggregation annotation, the UI
automatically takes this into consideration and no additional UI annotations are required.
For more information about the @DefaultAggregation annotation, see section DefaultAggregation Annotations
linked below.
You can use the following UI annotation to define what can be displayed in the title of a table or a list:
Sample Code
...
define view ZExample_SalesOrder as select from sepm_cds_sales_order as so {
@UI.lineItem: [ { position: 10 }, { qualifier: 'ValueList', position:
10 } ]
key so.sales_order_id as SalesOrder,
@UI.lineItem: [ { position: 30 } ]
so.currency_code as CurrencyCode,
@DefaultAggregation: #SUM
For more information about positioning, see section Positioning Fields linked below.
Related Information
Get information about what UI annotations to use to work with selection fields for SAP Fiori UIs.
If a CDS is annotated as @Search.searchable [page 443], the UI automatically takes this is into consideration
and no additional UI annotations are required to expose a search field or a value help.If your table or list
contains many data and therefore many rows, it gets hard to find the information you need. To facilitate finding
the desired information, you can use selection fields to specify the range of information that you are looking for.
If your table or list contains many data and therefore many rows, it gets hard to find theYou can use the
following UI annotation to enable specific elements for selection, for example using a filter bar:
Sample Code
...
define view ZExample_SalesOrder as select from sepm_cds_sales_order as so {
key so.sales_order_id as SalesOrder,
@UI.selectionField: [ { position: 10 } ]
so.customer.company_name as CompanyName,
...
}
Get an overview of how to use UI annotations for object-page floorplans for SAP Fiori UIs.
You can use the object-page floorplan if you need to display, create, or edit any object regardless of its
complexity level. You can use the object-page floorplan with either a facet (tabs) or flat (anchors) approach.
To expose a CDS view in an object-page floorplan, you can use the annotations explained in the following
sections:
Get information about what UI annotations to use to work with page headers of object-page floorplans for SAP
Fiori UIs.
The page header contains information on the object you are editing in the object-page floorplan, for example.
Sample Code
@UI.headerInfo: {
typeName: 'Sales Order',
title: {
label: 'Sales Order',
value: 'SalesOrder' -- Reference to element in element list
},
description: {
label: 'Customer',
value: 'CompanyName' -- Reference to element in element list
}
}
define view ZExample_SalesOrder as select from sepm_cds_sales_order as so {
key so.sales_order_id as SalesOrder,
so.customer.company_name as CompanyName,
...
}
●
This UI annotation can be considered as the combination of the UI annotations @UI.headerInfo [page 478]
and . The properties imageUrl, typeImageUrl and title should usually correspond to the properties of the UI
annotation @UI.headerInfo [page 478]. In addition to the title, a headLine, mainInfo and
secondaryInfo of the same format can be specified.
Sample Code
@UI.badge: {
title: {
label: 'Sales Order',
value: 'SalesOrderID' -- Reference to element in element list
},
headLine: {
label: 'Customer',
value: 'CompanyName' -- Reference to element in element list
},
mainInfo: {
label: 'Gross Amount',
value: 'GrossAmount' -- Reference to element in element list
},
secondaryInfo: {
label: 'Billing Status',
value: 'BillingStatus' -- Reference to element in element list
}
}
define view ZExample_SalesOrder as select from sepm_cds_sales_order as so {
key so.sales_order_id as SalesOrder,
so.customer.company_name as CompanyName,
so.gross_amount as GrossAmount,
so.billing_status as BillingStatus,
...
}
●
This UI annotation can be used to display status information of an entity on the UI, for example the delivery
status or payment status of an entity. This annotation is similar to the annotation. However, the annotation
is usually used together with the criticality property instead of the qualifier property.
...
define view ZExample_SalesOrder as select from sepm_cds_sales_order as so {
key so.sales_order_id as SalesOrder,
@UI.statusInfo: [ { position: 10 } ]
so.delivery_status as DeliveryStatus,
@UI.statusInfo: [ { position: 20 } ]
so.billing_status as BillingStatus,
@UI.statusInfo: [ { position: 30 } ]
so.lifecycle_status as LifecycleStatus,
...
}
Related Information
Get information about what UI annotations to use to work with page bodies of object-page floorplans for SAP
Fiori UIs.
The page body can consist of a list or a table, for example, in which you can see and edit details of an object
from the master-detail floorplan.
●
This annotation is similar to the UI annotation , but has no qualifier.
Sample Code
...
define view ZExample_SalesOrder as select from sepm_cds_sales_order as so {
@UI.identification: [ { position: 10 } ]
key so.sales_order_id as SalesOrder,
@UI.identification: [ { position: 20 } ]
so.customer.company_name as CompanyName,
@UI.identification: [ { position: 30 } ]
so.currency_code as CurrencyCode,
@UI.identification: [ { position: 40 } ]
so.gross_amount as GrossAmount
}
Related Information
Get information about what UI annotations to use to work with field groups for SAP Fiori UIs.
If you want to group fields under one heading to consolidate semantically connected information, you can use
field groups. With field groups, you can build sections for forms, for example.
●
This annotation is similar to the UI annotation because the different field groups have unique qualifiers.
Sample Code
Get an overview of how to use UI annotations that are similar to the OData annotation dataField.
The OData annotation dataField refers to a property of the OData service that is used.
Some annotations are syntactically similar or even identical. These annotations are the following:
●
●
You can use dataField-like annotations to reference elements from a different CDS view using to-one-
associations. You therefore need to explicitly define the elements with a value property. These elements are
then exposed to the UI.
Sample Code
...
define view ZExample_SalesOrder as select from sepm_cds_sales_order as so
association [0..1] to sepm_cds_business_partner as _BusinessPartner
on $projection.buyer_guid = _BusinessPartner.business_partner_key
{
key so.sales_order_id as SalesOrder,
so.buyer_guid,
...
@UI.Identification: [
{ value: '_BusinessPartner.company_name', position: 110 },
{ value: '_BusinessPartner.bp_role', position: 120 }
]
_BusinessPartner
}
Related Information
Get information about how to overwrite default labels for SAP Fiori UIs.
If a CDS element is exposed via a dataField-like annotation, the label is by default derived from the CDS
annotation @EndUsertText.label if available, or from a DDIC element.
If you want a default label to be overwritten by a specific label, for example Customer instead of Business, you
can use the label property.
Sample Code
...
define view ZExample_SalesOrder as select from sepm_cds_sales_order as so
association [0..1] to sepm_cds_business_partner as _BusinessPartner
on $projection.buyer_guid = _BusinessPartner.business_partner_key
{
key so.sales_order_id as SalesOrder,
so.buyer_guid,
...
@UI.Identification: [
{ value: '_BusinessPartner.company_name', position: 110, label: 'Customer
Name' },
{ value: '_BusinessPartner.bp_role', position: 120, label: 'Customer
Role’ }
]
_BusinessPartner
}
Related Information
Get information about how to change the position of fields on SAP Fiori UIs.
To define the order of fields in the UI, you can use the position property of dataField-like annotations. Only
the positioning order is relevant, so you can use any decimal number as value for the positioning property.
Sample Code
...
define view ZExample_SalesOrder as select from sepm_cds_sales_order as so {
@UI.identification: [ { position: 1 } ]
key so.sales_order_id as SalesOrder,
Related Information
Get information about how to set the priority of elements displayed on SAP Fiori UIs.
To define the priority of elements, you can use the importance property of dataField-like annotations. This
information is relevant for adaptive UIs. If a UI is displayed on a small screen, elements with low priority can
automatically be hidden. To define importance, you can choose the following values:
● #HIGH
● #MEDIUM
● #LOW
● not set
Sample Code
...
define view ZExample_SalesOrder as select from sepm_cds_sales_order as so {
@UI.identification: [ { position: 10, importance: #HIGH } ]
key so.sales_order_id as SalesOrder,
@UI.identification: [ { position: 40 } ]
so.gross_amount as GrossAmount
...
}
Get information about how to define the criticality of field values for SAP Fiori UIs.
To define if a field value is negative, critical, or positive, you can use the criticality property of dataField-like
annotations. This property must refer to a CDS element that has the value 1 (negative), 2 (critical), or 3
(positive).
Sample Code
...
define view ZExample_SalesOrder as select from sepm_cds_sales_order as so {
@UI.identification: [ { position: 10, importance: #HIGH } ]
key so.sales_order_id as SalesOrder,
...
@UI.statusInfo: [ { position: 10, criticality: 'GrossAmountCrit' } ]
so.billing_status as BillingStatus,
so.billing_status_crit as BillingStatusCrit,
...
}
Related Information
8.12.5 Charts
Get information about what UI annotations to visualize data on SAP Fiori UIs.
You can use the following UI annotation to define the properties of a chart:
●
You define this UI annotation at view level. It refers to the elements that are to be used in the chart.
Additionally, you can provide a title and description.
Sample Code
...
@UI.chart: {
title: 'Gross Amount by Customer',
description: 'Line-chart displaying the gross amount by customer',
chartType: #LINE,
dimensions: [ 'CompanyName' ], -- Reference to one element
measures: [ 'GrossAmount' ] -- Reference to one or more elements
}
define view ZExample_SalesOrder as select from sepm_cds_sales_order as so {
key so.sales_order_id as SalesOrder,
so.customer.company_name as CompanyName,
so.currency_code as CurrencyCode,
@Semantics.amount.currencyCode: 'CurrencyCode'
so.gross_amount as GrossAmount,
...
}
Related Information
8.12.5.1 Charts
Get an overview of what chart types you can use to visualize data on SAP Fiori UIs.
Each chart type has different restrictions referring to how many dimensions and measures are required or
allowed. The following table lists the admissible types and their restrictions.
COL
UMN_STACKED_100
AREA
AREA_STACKED
AREA_100
LINE
BAR_STACKED_100
HORIZONTAL_AREA
HORIZON
TAL_AREA_STACKED
HORIZON
TAL_AREA_100
Related Information
Get an overview of how to use data points to display criticality, trends, and references to people and time
periods on SAP Fiori UIs.
In some cases, you want to visualize a single point of data that typically is a number that can be enriched with
business-relevant data but may also be textual, for example a status value.
You can use the following UI annotation to define a single point of data:
Sample Code
...
define view ZExample_SalesOrdersByCustomer as select from ... as so {
key so.buyer_guid as BuyerGuid,
@Semantics.currencyCode: true
so.currency_code as CurrencyCode,
Related Information
8.12.6.1 Criticality
Get information about how to use data points to display criticality on SAP Fiori UIs.
A more usable variant of the UI annotation also contains information about the criticality, the trend, and the
name of a person responsible.
You can use the sub-annotation to express if a value is positive or negative, for example.
You can use the sub-annotation to express if a value has decreased or increased, for example.
In this case, the properties targetValue, criticality, and trend are already evaluated in the CDS view. In
the CDS view, the target value is already calculated, and if the current value thus is negative or positive, and if
the current value has improved or declined, for example. These values are only referred to from the annotation.
●
You define this UI annotation at view level. It refers to the elements that are to be used in the chart.
Additionally, you can provide a title and description.
The table below lists the values that are valid for the UI annotation , and shows how these values are
visualized on the UI:
1 Negative Red
2 Critical Yellow
3 Positive Green
Sample Code
...
define view ZExample_SalesOrdersByCustomer as select from ... as so {
key so.buyer_guid as BuyerGuid,
@Semantics.currencyCode: true
so.currency_code as CurrencyCode,
@UI.dataPoint: {
title: 'Gross Amount',
targetValueElement: 'TargetAmount', -- Reference to element
criticality: 'AmountCriticality', -- Reference to element
trend: 'AmountTrend', -- Reference to element
}
@Semantics.amount.currencyCode: 'CurrencyCode'
so.actual_amount as ActualAmount,
@Semantics.amount.currencyCode: 'CurrencyCode'
so.target_amount as TargetAmount,
so.criticality as AmountCriticality,
so.trend as AmountTrend
}
Related Information
Get information about how to use data points to display trends on SAP Fiori UIs.
Data can be defined as being either increasing, decreasing, or stable. These data can be measured over a
certain period of time and visualized on the UI.
Example
For an example, see the example code in section Criticality linked below.
Example
The table below lists the values that are valid for the UI annotation , and shows how these values are
visualized on the UI:
1 Strong up
2 Up
3 Sideways
4 Down
5 Strong down
For the trend calculation, the flag isRelativeDifference indicates whether the absolute or the relative
difference between the actual value and the reference value is used to calculate the trend.
Sample Code
...
define view ZExample_SalesOrdersByCustomer as select from ... as so {
key so.buyer_guid as BuyerGuid,
@Semantics.currencyCode: true
so.currency_code as CurrencyCode,
@UI.dataPoint: {
title: 'Gross Amount',
//...
trendCalculation: {
referenceValue: 'ReferenceAmount', -- Reference to element
isRelativeDifference: true, -- Comparison of ratio
strongUpDifference: 1.25,
upDifference: 1.1,
downDifference: 0.9,
strongDownDifference: 0.75
}
}
@Semantics.amount.currencyCode: 'CurrencyCode'
so.target_amount as TargetAmount,
@Semantics.amount.currencyCode: 'CurrencyCode'
so.reference_amount as ReferenceAmount
}
Related Information
Get information about how to use data points to calculate and display trend-criticality relations.
Another way to specify properties of criticality and trend is to define rules for criticality and trend within the UI
annotation .
You can use the following sub-annotations to calculate trends and derive from these calculation the criticality of
data:
●
●
Sample Code
...
define view ZExample_SalesOrdersByCustomer as select from ... as so {
key so.buyer_guid as BuyerGuid,
@Semantics.currencyCode: true
so.currency_code as CurrencyCode,
@UI.dataPoint: {
title: 'Gross Amount',
targetValue: 9216,
criticalityCalculation: {
improvementDirection: #TARGET,
toleranceRangeLowValue: 9200,
toleranceRangeHighValue: 9300,
deviationRangeLowValue: 8800,
deviationRangeHighValue: 9700
},
trendCalculation: {
referenceValue: 'ReferenceAmount', -- Reference to element
isRelativeDifference: false, -- Comparison of difference
strongUpDifference: 100,
upDifference: 10,
downDifference: -10,
strongDownDifference: -100
For the criticality calculation, the value of the property improvementDirection is crucial because this value
determines what further properties are needed. If, for example, the value is #MINIMIZE, the properties
ToleranceRangeHighValue and DeviationRangeHighValue are relevant.
The properties of the sub-annotation can have either constant values or derive values from referencing to other
elements. If a property references to another element, the suffix Element must be added to the name of the
property.
Note
This also applies to the properties of the sub-annotation , except for the property referenceValue. This
property always references to another element.
Example
Related Information
Get information about how to use data points to display references to persons responsible and to reference
periods on SAP Fiori UIs.
● referencePeriod
You can define both properties either in the UI annotation directly, or in another element and reference from
the UI annotation to this element.
Example
In the following example, the data point has a static reference period and a static person responsible. The
value of the gross amount is formatted with the valueFormat property. The value is thus scaled with
factor 1000 and is displayed with one decimal place, this is the value 34500 EUR would be displayed as
34.5 kEUR.
Sample Code
...
define view ZExample_SalesOrdersByCustomer as select from ... as so {
key so.buyer_guid as BuyerGuid,
@Semantics.currencyCode: true
so.currency_code as CurrencyCode,
@UI.dataPoint: {
title: 'Gross Amount',
description: 'Gross Amount per Customer',
longDescription: 'The gross amount per customer ...',
valueFormat: {
scaleFactor: 1000,
numberOfFractionalDigits: 1
},
referencePeriod: { description: '2015 Q3' },
responsibleName: 'John Doe'
}
@Semantics.amount.currencyCode: 'CurrencyCode'
so.actual_amount as ActualAmount
}
In the following example, a dynamic reference period is used that is supplied by the following parameters:
● start
● end
These parameters have to be aliased in the element list before they can be used in the annotation. The
responsible property must refer to a to-one-association. The target entity of this association should contain
the contact data of the person responsible.
Sample Code
...
define view ZExample_SalesOrdersByCust
with parameters p_StartDate : abap.dats,
p_EndDate : abap.dats
as select from ... as so
association [0..1] to Employees as _PersonResponsible
on _PersonResponsible.EmployeeId = $projection.PersonResponsible
{
...
$parameters.p_StartDate as StartDate, -- Alias is required for
annotation
$parameters.p_EndDate as EndDate, -- Alias is required for
annotation
so.person_responsible as PersonResponsible,
@Semantics.currencyCode: true
so.currency_code as CurrencyCode,
@UI.dataPoint: {
title: 'Gross Amount',
referencePeriod: {
start: 'StartDate', -- Reference to element
end: 'EndDate' -- Reference to element
},
responsible: '_PersonResponsible' -- Reference to association
}
@Semantics.amount.currencyCode: 'CurrencyCode'
@DefaultAggregation: #SUM
so.actual_amount as ActualAmount,
_PersonResponsible
}
where so.validity_date >= $parameters.p_StartDate
and so.validity_date <= $parameters.p_EndDate
Related Information
Get information about how to use the type #AS_DATAPOINT to refer to other annotations.
You can use the following type to reference an exposed data point from dataField-like annotations:
● #AS_DATAPOINT
You use this type to include a microchart in the UI annotation , for example.
Example
In this example, the UI annotation has to be defined at the same CDS element as the UI annotation itself.
Sample Code
...
define view ZExample_SalesOrdersByCustomer as select from ... as so {
key so.buyer_guid as BuyerGuid,
...
@Semantics.currencyCode: true
so.currency_code as CurrencyCode,
Related Information
Get information about what UI annotations to use to display contact data on SAP Fiori UIs.
In some cases users of an application need to see contact data, for example, of business partners, customers,
or employees.
You can use the following annotation set to inform a client that an entity contains contact information and map
the CDS elements to the corresponding address field:
Example
The following example contains sub-annotations belonging to the annotation set @Semantics. For a
complete list, see section Semantics Annotations linked below.
Sample Code
...
define view Employees as select from ...
{
key EmployeeId,
@Semantics.name.givenName
FirstName,
@Semantics.name.additionalName
MiddleName,
@Semantics.name.familyName
LastName,
GenderCode,
@Semantics.telephone.type: [#WORK, #PREF]
PhoneNumber,
@Semantics.telephone.type: [#FAX]
FaxNumber,
@Semantics.telephone.type: [#CELL]
MobilePhoneNumber,
@Semantics.eMail.address
EmailAddress,
PreferredLanguage,
@Semantics.contact.birthDate
BirthDate
}
Related Information
8.12.8 Navigation
Get an overview of how to use dataField types to provide means of navigation on SAP Fiori UIs.
It often is not sufficient to stay on one screen. Users might need to navigate between screens or even to web
sites outside an application. You can use the following dataField types ton include navigation concepts:
Get information about how to provide navigation between UI screens and pages on SAP Fiori UIs.
This navigation type contains either a navigation property or a term cast. The term either is of type
Edm.EntityType, a concrete entity type, or a collection of these types.
You can use the following dataField type to expose a link to other pages of a UI:
● #WITH_NAVIGATION_PATH
Example
...
define view ZExample_SalesOrder as select from sepm_cds_sales_order as
so
association [0..1] to sepm_cds_business_partner as _BusinessPartner
on $projection.buyer_guid = _BusinessPartner.business_partner_key
{
key so.sales_order_id as SalesOrder,
so.buyer_guid,
...
@UI.lineItem: [ {
position: 20,
type: #WITH_NAVIGATION_PATH,
targetElement: '_BusinessPartner' -- Reference to association
} ]
so.customer.company_name as CompanyName,
...
_BusinessPartner
}
Related Information
Get information about how to provide navigation from SAP Fiori UIs to external web sites, for example.
This type navigation type contains a reference to a URL to navigate to specific web sites, for example.
You can use the following dataField type to display links to external websites:
● #WITH_URL
Example
In the following example, CompanyName is displayed as link referring to the CDS element WebsiteUrl.
Sample Code
...
define view ZExample_SalesOrder as select from sepm_cds_sales_order as
so
{
key so.sales_order_id as SalesOrder,
...
@UI.lineItem: [ {
position: 20,
type: #WITH_URL,
url: 'WebsiteUrl' -- Reference to element
} ]
so.customer.company_name as CompanyName,
Related Information
Get information about how to provide navigation related on actions that are executed on SAP Fiori UIs.
This navigation type contains an action that is related to a semantic object. This combination of action and
semantic object is an intent. The annotation is required for navigation based on intent. The client decides how
to react when this navigation is triggered.
You can use the following dataField type to expose the intent to navigate without specifying how this navigation
is to be resolved:
● #FOR_INTENT_BASED_NAVIGATION
Example
In the following example, the intent 'Show' (action) 'BusinessPartner' (semantic object) is
expressed. The client can, for example, open a separate application to display the details of the
corresponding business partner.
Sample Code
...
define view ZExample_SalesOrder as select from sepm_cds_sales_order as
so
{
@UI.lineItem: [ {
position: 20,
label: 'Show customer-details',
type: #FOR_INTENT_BASED_NAVIGATION,
semanticObjectAction: 'Show' -- Action
} ]
@Consumption.semanticObject: 'BusinessPartner' -- Semantic Object
so.customer.company_name as CompanyName,
...
}
Related Information
8.12.9 Actions
Get information about how to use dataField types to provide means of executing actions on SAP Fiori UIs.
Actions are directly related to items that you can see in a table on a master-detail floorplan, for example. Users
can select items and execute certain actions on the selected items.
You can use the following dataField type to expose actions to the client:
● #FOR_ACTION
This property has to be assigned to some arbitrary element. It is thereby irrelevant if the property refers to
the element to which the property is assigned.
Sample Code
...
define view ZExample_SalesOrder as select from sepm_cds_sales_order as so {
@UI.lineItem: [
-- Standard Lineitem
{ position: 10 },
-- Action Lineitem
{ type: #FOR_ACTION, dataAction: 'BOPF:Copy', label: 'Copy' }
]
key so.sales_order_id as SalesOrder,
...
Get information about what UI annotations to use to manipulate fields for SAP Fiori UIs.
This chapter describes annotations that influence the appearance exposed fields. When a field is marked with
these annotations, it is manipulated no matter in what other annotations the field is used. The reason for this is
that annotations for manipulation are self-contained annotations and not properties of other annotations.
For example, when a field is marked with the annotation, the field is masked regardless if it is used in a
annotation or a annotation.
To manipulate the appearance of fields on SAP Fiori UIs, you can use the annotations explained in the following
sections:
Get information about what UI annotations to use to display fields as multi-line text on SAP Fiori UIs.
You can use the following annotation to mark a field to be displayed by a control that supports multi-line input,
for example a text area:
Sample Code
...
define view Product as select from ... {
@UI.identification: [ { position: 10 } ]
key ProductID,
@UI.identification: [ { position: 20 } ]
ProductName,
@UI.identification: [ { position: 30 } ]
@UI.multiLineText: true
Description,
...
}
Get information about what UI annotations to use to mask fields, for example for password input, on SAP Fiori
UIs.
In some cases, data of fields need to be consumed by the client, but must not be visible on the UI. This field
behavior is required when users need to enter passwords, for example.
You can use the following annotation to mark a field to not to be displayed in clear text by the client because, for
example, it contains sensitive data:
●
This annotation does not influence how data is transferred. If a field is marked with the annotation, the
data belonging to this field is still transferred to the client like any other property in clear text.
Sample Code
...
define view Destination as select from ... {
@UI.identification: [ { position: 10 } ]
key DestinationID,
...
@UI.identification: [ { position: 20 } ]
AuthType, -- None, Basic, SSO, ...
@UI.identification: [ { position: 30 } ]
BasicAuthUserName,
@UI.identification: [ { position: 40 } ]
@UI.masked
BasicAuthPassword,
...
}
Related Information
Get information about what UI annotations to use hide fields from SAP Fiori UIs.
Generally, all fields that are exposed by the OData service are available to the client, regardless if the fields are
exposed explicitly using UI annotations. To enable end-user personalization, the client may offer the possibility
to add fields that are hidden by default, for example to a list report.
You can use the following annotation to prevent fields from being displayed on a UI and in the personalization
dialog, but leaving the field available for client:
●
You can use this annotation if, for example, a CDS view contains technical keys, for example GUIDs, that
have to be exposed to the OData service to work. These keys are usually not supposed to be displayed on
the UI. You can also use this annotation if fields are required in calculations, but are not supposed to be
displayed on a UI.
Example
In the following example, the annotation with pre-calculated criticality and trend is exposed. The hidden
fields AmountCriticality and AmountTrend are required by the client to calculate the
corresponding values, but are not supposed to be displayed on the UI.
Sample Code
...
define view ZExample_SalesOrdersByCustomer as select from ... as so {
@UI.hidden
key so.buyer_guid as BuyerGuid,
...
@UI.dataPoint: {
criticality: 'AmountCriticality', -- Reference to element
trend: 'AmountTrend', -- Reference to element
}
so.actual_amount as ActualAmount,
@UI.hidden
so.criticality as AmountCriticality,
@UI.hidden
so.trend as AmountTrend
}
You can use the following annotation to prevent fields from being available to a client:
●
Preventing fields from being available to a client is necessary for system parameters. These parameters are
filled by the runtime engine, but must not be available to the client.
Sample Code
...
define view OverdueSalesOrder with parameters
@Consumption.hidden : true
@Environment.systemField : #SYSTEM_DATE
P_Date : sydate,
as select from ...
{
...
For more information about consumption annotations, see section Consumption Annotations linked below.
Example
In the following example, the field buyer_guid is required by the association to _BusinessPartner only.
This means, the field must be included in the element list of the CDS view, but must not be transferred to
the client.
Sample Code
...
define view ZExample_SalesOrder as select from sepm_cds_sales_order as so
association [0..1] to sepm_cds_business_partner as _BusinessPartner
on $projection.buyer_guid = _BusinessPartner.business_partner_key
{
key so.sales_order_id as SalesOrder,
@Consumption.hidden: true
so.buyer_guid,
...
_BusinessPartner
}
There may be cases, where a field is needed in the client, for example for calculations, but should not be
displayed directly in a list or table, or on an object-page floorplan. In this case the annotation is not suitable.
Related Information
In addition to UI annotation, you can use model-specific annotations that affect the desired client behavior. You
can implement, for example, unit-currency-mappings, ID-text-mappings, or properties for field control that are
represented by model-specific annotations. These model-specific annotations can be evaluated by the client
and no additional UI annotations are required.
Example
In the following example, the field CurrencyCode is marked with a @Semantics.currencyCode [page 456]
and is referenced by field GrossAmount. This means that the field GrossAmount is always displayed with
the corresponding currency. The field CurrencyCode does not need to be exposed explicitly.
Futhermore the field GrossAmount is marked as being mandatory. This means that the field is treated
accordingly by the client: The field is marked with an asterisk, and if users do not fill in a value for this
property, an error is raised. The administrative fields such as CreatedAt and CreatedBy, are set in a
back-end validation and must not be changed by the client. For this reason, these fields are marked as
being read-only.
Sample Code
...
define view ZExample_SalesOrder as select from sepm_cds_sales_order as so
{
@UI.identification: [ { position: 10 } ]
key so.sales_order_id as SalesOrder,
@Semantics.currencyCode: true
so.currency_code as CurrencyCode,
@Semantics.amount.currencyCode: 'CurrencyCode'
@ObjectModel.mandatory: true
@UI.identification: [ { position: '20' } ]
so.gross_amount as GrossAmount,
...
@ObjectModel.readOnly: true
@UI.identification: [ { position: '110' } ]
so.created_at as CreatedAt,
@ObjectModel.readOnly: true
@UI.identification: [ { position: '120' } ]
so.created_by as CreatedBy,
@ObjectModel.readOnly: true
@UI.identification: [ { position: '130' } ]
so.changed_at as ChangedAt,
@ObjectModel.readOnly: true
@UI.identification: [ { position: '140' } ]
so.changed_by as ChangedBy,
}
Get information about what property to use to prevent elements from being inherited from an underlying CDS
view.
By default, all UI annotation elements are inherited from the underlying CDS view. You can explicitely disable
this behavior. You can use the following property to prevent a UI annotation element from being inherited:
● exclude
The following sample code depicts the CDS view ZP_SalesOrder that inherits elements from the
underlying CDS view SEPM_CDS_SALES_ORDER, and uses the UI annotation :
Sample Code
...
define view ZP_SalesOrder as select from sepm_cds_sales_order as so {
@UI.identification: [ { position: 10 } ]
key so.sales_order_id as SalesOrder,
@UI.identification: [ { position: 20 } ]
so.customer.company_name as CompanyName,
...
}
The following sample code depicts the CDS view ZI_SalesOrder that inherits elements from the
underlying CDS view ZP_SalesOrder. In this view, the element key SalesOrder is inherited from the
underlying CDS view as UI annotation by default. The element so.customer.company_name as
CompanyName, however, is not inherited as UI annotation because of the property exclude:
Sample Code
...
define view ZI_SalesOrder as select from ZP_SalesOrder as so {
key SalesOrder,
@UI.identification: [ { exclude } ]
so.customer.company_name as CompanyName,
...
}
Auto-Exposure Let us assume that you created a quite elementary data ABAP Develop Generating OData
model based on multiple CDS views. All these views together ment Tools Service With Auto-
form a quite simple composition: One CDS view serves as Exposure [page
root and the other CDS entities are children of your root CDS 19]
view. The CDS views of this composition might also have as
sociations to other entities.
Use Case 2:
You created a CDS view that contains features that are not
supported by CDS or complex CDS view compositions. You
need to implement these features manually in the model
provider extension class (MPC_EXT class) or in the data pro
vider extension class of your Service Builder project. To pro
vide, for example, dynamic field control, you need to imple
ment custom logic in a model provider extension class.
Mapped Data You modeled an entity set in transaction SEGW from a DDIC Transaction SEGW Generating an
Source (MDS) structure. You want to map fields of a CDS view to your cus OData Service Us
tom model. You furthermore want to reference from your ing the Mapping
custom model to another CDS view, for example, and there Editor [page 350]
fore need to map the two different entity sets.
Caution
Future changes of the entities might invalidate the serv
ice runtime.
OData Exposure
With the concept of auto-exposure, a new and simple way of creating OData services has been introduced.
Here, the OData model definition as well as the OData service runtime is provided generically, based on SADL
(Service Adaptation Description Language).
The requirement here is that the annotation @OData.publish:true is specified at the CDS data model (CDS
consumption view) level as follows:
@AbapCatalog.sqlViewName: 'SQL_VIEW_SAMPLE'
...
@OData.publish: true
define view CDS_VIEW_NAME as select from
...
}
Remember
We recommend using the auto-exposure option in the case of elementary data model compositions: for
example, if you defined the entire CDS data model based on a root CDS view so that several other CDS
views are children of this root CDS view. In addition, the CDS views of this composition might have
associations to other entities. In cases like this, all the CDS views together form a quite simple data model
composition that you want to expose as an OData service, together with first the level of associations.
● Your data model composition is more complex and you need to include deeper association levels in
your OData service.
● You want to generate a hybrid scenario where implementations are based on CDS views and on custom
logic.
The following figure depicts the main components of the auto-exposure process and refers to the most
important activities that are involved:
Starting in ABAP Development Tools, you open the relevant CDS data definition object where the CDS view in
question is implemented. After you have added the OData annotation to the CDS view, you can trigger the
activation of the entire CDS data definition (that serves as transportable development object). ABAP
Development Tools delegates the activation request to SADL. SADL framework generates several SAP Gateway
artifacts that are stored in the back end of the application server AS ABAP and are required for OData service
activation in the SAP Gateway hub system.
As soon as the OData service is activated in the SAP Gateway hub, it is ready for consumption through an
OData client, such as an SAP Fiori app.
Included components and involved activities when exposing CDS-based data model to OData
Developer-Relevant Tasks
As a result of this task, several service artifacts are generated in the back end of the application server.
Task 2: Activate OData Service in the SAP Gateway Hub [page 22]
As a result of this task, the OData service is added to service catalog of the SAP Gateway hub and is ready for
consumption.
Use Case
You want to generate an OData services with a CDS entity (CDS view) as a referenced data source. The CDS
model and the CDS annotations fully specify the OData Model and the runtime behavior, without any additional
This tool supported approach allows you more flexibility concerning the creation of an OData Service: In
contrast to the auto-exposure, you can add additional entities or make structure changes or manipulate data, if
necessary, to adapt the OData Service to your specific requirements. This approach is advisable if you want to
use custom code to change the OData Service instead of having the OData Service and the runtime artifacts
autogenerated.
Prerequisites
● Knowledge
○ You require advanced knowledge of the SAP Gateway Service Builder and OData.
○ Your require basic knowledge of the Enterprise Procurement Model (EPM).
● Systems and Releases
○ This function is provided as of Netweaver Release 7.5 SP00.
● Authorizations
○ The user needs access and the appropriate authorization in order to run the SAP Gateway Service
Builder.
Projects are used to store the artifacts that developers need to create a service and its underlying data model
in a single place in the SAP Gateway Service Builder.
Process Steps
1. Enter transaction code SEGW to access the SAP Gateway Service Builder.
Note
The other options are not relevant if you want to create an Odata Service based on a referenced
data source.
Related Information
You can use the data model defined in an CDS entity created earlier, where the CDS model and the CDS
annotations fully specify the OData model and the runtime behavior as a referenced data source. You can
adapt and change the imported data model, for example by adding associations or further CDS entities.
Process Steps
1. Enter transaction code SEGW to access the SAP Gateway Service Builder.
2. Create a project as described in Creating a Project [page 343].
3. Right-click on the Data Model folder and choose Reference Data Source .
4. Enter the name of the CDS entity you want to use as referenced data source in the CDS Entity field and
choose Next.
5. The second page of the wizard is opened and the data model of the selected CDS entity is displayed. You
can choose which entities and associations you want to expose with your OData Service.
Note
When you select an association, the target entity is automatically selected as well. If you deselect the
association, you can select the target entities separately.
7. Here you can adapt your data model or add additional CDS entities as data sources. You can display the
source entity, the association, and the target entity of each listed entity to get more details.
Note
By default, only the first level of association is listed in the CDS Entity Exposure column. If you want to
add more levels to the model, right-click the required entity and select Add CDS Entity.
Result
You have imported the Referenced Data Source and selected the entities you want to expose. You can now
generate the Runtime Artifacts.
Related Information
You must generate the Runtime Artifacts after you have defined the metadata for them. When you generate the
Runtime Artificats in the SAP Service Builder, it automatically generates the code for making your service
OData-compliant and ready for use in SAP Gateway. In addition, the Service Builder automatically configures
the project by assigning the data model to the generated service for use at runtime.
● The implementation classes for the data model and the service are automatically created.
● The OData service is automatically registered in SAP Gateway.
Process Steps
1. Enter transaction code SEGW to access the SAP Gateway Service Builder.
2. Create a project as described in Creating a Project [page 343]
3. Define your data model.
4. Click to generate the Runtime Artifacts for your project. The OData service is registered in the back
end and the Model Provider Classes and the Data Provider Classes are automatically generated in the
Runtime Artifacts folder of your project.
Note
If a project is generated for the first time, you have to specify the Technical Model Name and the
Techncial Service Name. The technical service name is used when the OData service is published and
cannot be changed after that.
Result
Project_Name_MDL The technical model name that is used to register the serv
ice in the SAP Business Suite system and is automatically
generated.
Project_Name_SRV The technical service name that is used to register the serv
ice in the SAP Business Suite system and is automatically
created.
Z_CL_Project_Name_RDS_MPC The model provider base class contains redefinitions for the
DEFINE() and GET_LAST_MODIFIED() methods.
Related Information
The model provider contains the ABAP code that defines the data model of the OData Service at runtime.
● ZCL_Project_Name_MPC: The model provider base class is derived from the superclass /IWBEP/
CL_MGW_ PUSH_ABS_MODEL. and contains redefinitions for the DEFINE() and GET_LAST_MODIFIED()
methods.
For more information about the model provider base class and the methods it contains, see Base Class:
Model Provider Class
● ZCL_Project_Name_MPC_EXT:
This extension class is inherited from the model provider base class and inherits its properties. The model
provider extension class is registered in the back end using the technical service name. In this class, you
can choose which methods of the base class you want to keep and which methods you want to redefine to
suit your requirements. For more information, about the model provider implementation class, see
Implementation Class: Model Provider Class
The data provider classes contain the OData service operation implementation.
● ZCL_Project_Name_DPC: Generating the runtime artifacts redefines and implements the following
operations: Create, Read, Update, Delete (CRUD), and Query. The class is generated only when the Service
Builder successfully generates the code for the classes of the model provider class (MPC). The DPC base
class inherits from the generic runtime class /IWBEP/CL_MGW_PUSH_ABS_DATA. Fore more details about
the data provider base class, see Base Class: Data Provider Class .
● ZCL_Project_Name_DPC_EXT: This implementation class inherits its properties from data provider base
class. You can redefine each method in the implementation class for the data provider class. For more
details about how to redefine methods, see Redefining Methods of the Operations
You need to register your OData Service for use in each system.
Prerequisites
The SAP Gateway systems in which you want to register the OData service must be configured under the
following path: SPRO SAP NetWeaver SAP Gateway Service Enablement Backend OData Channel
Connection Settings to SAP Gateway SAP Gateway Settings . This is done to assign the RFC destination to
the specific SAP Gateway system you want to use with the SAP Service Builder..
1. Enter transaction code SEGW to access the SAP Gateway Service Builder.
2. Create a project as described in Creating a Project [page 343].
3. Define your data model.
4. Generate your Runtime Artifacts as described in Generating Runtime Artifacts [page 345].
5. Expand the Service Maintenance folder in your project. This list contains all configured systems for which
you can register your OData service.
Tip
You can double-click to view the configured systems in the mass maintenance view to check whether
the Odata Service has already been registered for your target system.
6. Right-click on a system for which you want to register the OData service and select Register. The Select
System Alias window is displayed if there is more than one system that points to the system from which
you are registering the OData service. Select your target system by using the input help available for this
field.
7. Click Continue to display the Add Service window. The details about the selected target system are
displayed. Choose a package and click Continue.
Result
The OData service is now registered for the system in question and the registration status turns green.
You can use the SAP Gateway Client to test your OData Service and see if it works as expected.
Process Steps
1. Enter transaction code SEGW to access the SAP Gateway Service Builder.
2. Create a project as described in Creating a Project [page 343].
3. Define your data model.
4. Generate the Runtime Artifacts as described in Generating Runtime Artifacts [page 345].
5. Register the OData Service as described in Registering an OData Service [page 348].
6. Click SAP Gateway Client to launch the SAP Gateway Client to test your OData service.
7. The SAP Gateway Client is opened with a prefilled request URL.
Tip
If you want to know more about the SAP Gateway Client, seeSAP Gateway Client .
SADL offers a mapping editor in the SAP NetWeaver Gateway Service Builder to bind one or several SADL
models to OData entity sets. This enables you to use SADL models as an additional data source besides RFC
and others. Once the OData properties are mapped, the system provides a standard, optimized
implementation of the OData service to retrieve the data.
Prerequisites
● You are familiar with working with SAP NetWeaver Gateway Service Builder. For information about the
Gateway Service Builder, see SAP Help Portal at help.sap.com at Technology SAP NetWeaver Platform
<Release> Application Help Function-Oriented View SAP NetWeaver Gateway Foundation
(SAP_GWFND) SAP NetWeaver Gateway Foundation Developer Guide SAP NetWeaver Gateway Service
Builder .
● You have access to the back-end system and are authorized to log on to this system and to generate and
register OData Services. For information about required authorizations, see SAP Help Portal at
help.sap.com at Technology SAP NetWeaver Platform <Release> Application Help Function-
Oriented View SAP NetWeaver Gateway Foundation (SAP_GWFND) SAP NetWeaver Gateway
Configuration Guide OData Channel Configuration User, Developer, and Administrator Authorizations .
Procedure
1. In SAP NetWeaver Gateway Service Builder, create a project and define the OData model.
2. Open the Service Implementation node, right-click on an entity set and choose Map to Data Source.
When you implement a SADL-based OData service, you map the complete entity set. This differs from the
usual procedure, where you map each operation (Create, Read, and so on) separately.
3. Choose the data source type and open the value help for the Name field.
4. Choose the SADL model by selecting a SADL Model Source and SADL Model Name.
The options you see here, depend on what is available in the system. Usually you should see DDIC and
CDS.
5. To map the entities, associations and actions, you have the following options:
○ You can switch between the Property Editor, Association Editor, and the Action Editor. From the editor
you are currently working in, you can switch to the other two possible editors.
○ Generate a mapping proposal by choosing Generate Mapping. This compares the ABAP field names of
the properties with the names in the SADL entity tree. Upper and lower case as well as underscores are
ignored. Only the highest level of the entity tree is compared. If both values are the same, you will see
that the SADL entity name has been entered in the Element column of the mapping table. You have to
generate the mapping for entities and associations separately.
○ Create the mapping by dragging the elements from the SADL tree and dropping them on the
corresponding cell in the Elements column of the mapping table.
Related Information
Projects are used to store the artifacts that developers need to create a service and its underlying data model
in a single place in the SAP Gateway Service Builder.
Process Steps
1. Enter transaction code SEGW to access the SAP Gateway Service Builder.
Note
The other options are not relevant if you want to create an Odata Service based on a referenced
data source.
Result
Related Information
Mapping is a manual relation that you establish between the parameters of a data source object (in an SAP
backend system) and the properties of an entity set in the Service Builder. When you implement a SADL-based
OData service, you map the complete entity set in contrast to the usual procedure, where you map each
operation (Create, Read, and so on) separately,
Process Steps
1. Enter transaction code SEGW to access the SAP Gateway Service Builder.
2. Create a project as described in Creating a Project [page 343]
3. Define your Odata model.
4. Open the Service Implementation node, right-click on an entity set and choose Map to Data Source.
Note
When you implement a SADL-based OData service, you map the complete entity set. This differs from
the usual procedure, where you map each operation (Create, Read, and so on) separately.
5. Choose the data source type and open the value help for the Name field.
6. Choose the SADL model by selecting a SADL Model Source and SADL Model Name.
Note
The options you see here, depend on what is available in the system. Usually you should see DDIC and
CDS
7. To map the entities, associations and actions, you have the following options:
○ You can switch between the Property Editor, Association Editor, and the Action Editor. From the editor
you are currently working in, you can switch to the other two possible editors.
○ Generate a mapping proposal by choosing Generate Mapping. This compares the ABAP field names of
the properties with the names in the SADL entity tree. Upper and lower case as well as underscores are
ignored. Only the highest level of the entity tree is compared. If both values are the same, you will see
that the SADL entity name has been entered in the Element column of the mapping table. You have to
generate the mapping for entities and associations separately.
○ Create the mapping by dragging the elements from the SADL tree and dropping them on the
corresponding cell in the Elements column of the mapping table.
8. Generate your Runtime Artifacts as described in Generating Runtime Artifacts [page 345].
You have mapped your entity set and thubound one or several SADL models to OData entity sets. You can now
generate your Runtime Artifacts and register your Odata service.
Related Information
You must generate the Runtime Artifacts after you have defined the metadata for them. When you generate the
Runtime Artificats in the SAP Service Builder, it automatically generates the code for making your service
OData-compliant and ready for use in SAP Gateway. In addition, the Service Builder automatically configures
the project by assigning the data model to the generated service for use at runtime.
● The implementation classes for the data model and the service are automatically created.
● The OData service is automatically registered in SAP Gateway.
Process Steps
1. Enter transaction code SEGW to access the SAP Gateway Service Builder.
2. Create a project as described in Creating a Project [page 343]
3. Define your data model.
4. Click to generate the Runtime Artifacts for your project. The OData service is registered in the back
end and the Model Provider Classes and the Data Provider Classes are automatically generated in the
Runtime Artifacts folder of your project.
Note
If a project is generated for the first time, you have to specify the Technical Model Name and the
Techncial Service Name. The technical service name is used when the OData service is published and
cannot be changed after that.
Project_Name_MDL The technical model name that is used to register the serv
ice in the SAP Business Suite system and is automatically
generated.
Project_Name_SRV The technical service name that is used to register the serv
ice in the SAP Business Suite system and is automatically
created.
Z_CL_Project_Name_RDS_MPC The model provider base class contains redefinitions for the
DEFINE() and GET_LAST_MODIFIED() methods.
Related Information
The model provider contains the ABAP code that defines the data model of the OData Service at runtime.
● ZCL_Project_Name_MPC: The model provider base class is derived from the superclass /IWBEP/
CL_MGW_ PUSH_ABS_MODEL. and contains redefinitions for the DEFINE() and GET_LAST_MODIFIED()
methods.
For more information about the model provider base class and the methods it contains, see Base Class:
Model Provider Class
● ZCL_Project_Name_MPC_EXT:
This extension class is inherited from the model provider base class and inherits its properties. The model
provider extension class is registered in the back end using the technical service name. In this class, you
can choose which methods of the base class you want to keep and which methods you want to redefine to
suit your requirements. For more information, about the model provider implementation class, see
Implementation Class: Model Provider Class
The data provider classes contain the OData service operation implementation.
● ZCL_Project_Name_DPC: Generating the runtime artifacts redefines and implements the following
operations: Create, Read, Update, Delete (CRUD), and Query. The class is generated only when the Service
Builder successfully generates the code for the classes of the model provider class (MPC). The DPC base
class inherits from the generic runtime class /IWBEP/CL_MGW_PUSH_ABS_DATA. Fore more details about
the data provider base class, see Base Class: Data Provider Class .
● ZCL_Project_Name_DPC_EXT: This implementation class inherits its properties from data provider base
class. You can redefine each method in the implementation class for the data provider class. For more
details about how to redefine methods, see Redefining Methods of the Operations
You need to register your OData Service for use in each system.
Prerequisites
The SAP Gateway systems in which you want to register the OData service must be configured under the
following path: SPRO SAP NetWeaver SAP Gateway Service Enablement Backend OData Channel
Connection Settings to SAP Gateway SAP Gateway Settings . This is done to assign the RFC destination to
the specific SAP Gateway system you want to use with the SAP Service Builder..
Process Steps
1. Enter transaction code SEGW to access the SAP Gateway Service Builder.
2. Create a project as described in Creating a Project [page 343].
3. Define your data model.
4. Generate your Runtime Artifacts as described in Generating Runtime Artifacts [page 345].
5. Expand the Service Maintenance folder in your project. This list contains all configured systems for which
you can register your OData service.
Tip
You can double-click to view the configured systems in the mass maintenance view to check whether
the Odata Service has already been registered for your target system.
6. Right-click on a system for which you want to register the OData service and select Register. The Select
System Alias window is displayed if there is more than one system that points to the system from which
you are registering the OData service. Select your target system by using the input help available for this
field.
7. Click Continue to display the Add Service window. The details about the selected target system are
displayed. Choose a package and click Continue.
The OData service is now registered for the system in question and the registration status turns green.
You can use the SAP Gateway Client to test your OData Service and see if it works as expected.
Process Steps
1. Enter transaction code SEGW to access the SAP Gateway Service Builder.
2. Create a project as described in Creating a Project [page 343].
3. Define your data model.
4. Generate the Runtime Artifacts as described in Generating Runtime Artifacts [page 345].
5. Register the OData Service as described in Registering an OData Service [page 348].
6. Click SAP Gateway Client to launch the SAP Gateway Client to test your OData service.
7. The SAP Gateway Client is opened with a prefilled request URL.
Tip
If you want to know more about the SAP Gateway Client, seeSAP Gateway Client .
It is possible to expose CDS views with parameters. Parameters can be used for calculations and data
selections within a CDS view. Parameter values must be supplied for each DB query. Using specific
annotations, you can decide whether values for parameters should be provided by OData consumers (visible
parameter) or filled internally by the ABAP server, and thus cannot be influenced by OData consumers (hidden
parameters). Visible and hidden parameters can also be combined in a single CDS view.
Visible Parameters
The following is an example of a CDS view with a Currency parameter, which has to be supplied by the OData
consumer to receive amounts converted to a required currency:
In the case of views with visible parameters, the mapping of CDS artifacts to the OData metamodel is different,
since the parameter values need to be supplied before executing any OData queries. As a consequence, a CDS
view with parameters has to be mapped to two OData enttity sets - parameter and result entity set. Let's
suppose the name of the CDS view is 'CDSView'. The OData artifact names would be as follows:
OData Name
Note
A DDIC data element must be used to delcare the type of visible parameters.
Note
CDS views with visible parameters must not expose any associations and must not be a target view of an
exposte association.
Note
If the CDS view is analytical, a different naming convention is used for the generated OData artifacts.
Hidden Parameters
Parameter annotations can be used to specify that a parameter should be hidden and thus not visible for
OData consumers. The system fills the parameters from system variables. The annotation looks as follows:
Here, the view parameter p_user is not exposed. The parameter is bound to the system variable sy-uname at
runtime .
#CLIENT SY-MANDT
#SYSTEM_LANGUAGE SY-LANGU
#APPLICATION_USER SY-UNAME
#SYSTEM_DATE SY-DATUM
#SYSTEM_TIME SY-UZEIT
Note
Analytical Scenarios
CDS also covers analytical scenarios, where measures and dimensions can be defined. The runtime of these
CDS views is provided by the Analytical Engine or by SADL, depending on the complexity of the view.
Note
A CDS view is considered to be an analytical view if it contains at least one occurrence of the
@DefaultAggregation annotation.
For more information about analytical entities, seeUsing Aggregate Data in SAP Fiori Apps [page 263].
The following is an example of a CDS view with a Currency parameter, which has to be supplied by the OData
consumer to receive amounts converted to a required currency. This view also has additional analytical
annotations.
In the case of views with visible parameters, the mapping of CDS artifacts to the OData metamodel is different,
since the parameter values do not need to be supplied before executing an OData query. As a consequence, a
CDS view with parameters and analytical annotations has to be mapped to two OData entity sets - parameter
OData Name
OData Association
The following list summarizes all SAP annotations of the Data Definition Language (DDL) of ABAP CDS.
SAP CDS annotations are evaluated by SAP frameworks and can be either ABAP annotations or framework-
specific annotations.
● AbapCatalog Annotations
● AccessControl Annotations
● ClientDependent Annotations (obsolete as of SAP NetWeaver AS for ABAP 7.51 innovation package SP00)
● ClientHandling Annotations
● DataAging Annotations
● EndUserText Annotations
● Environment Annotations
● MappingRole Annotations
● Metadata Annotations
● Semantics Annotations
Tip
To access help for an ABAP annotation, position the cursor on the relevant annotation in the DDL editor and
choose F1 .
Framework-Specific Annotations
CDS annotations that (as a rule) are evaluated during runtime by specific frameworks such as SADL, BOPF,
Analytics, or Enterprise Search:
Related Information
Enable application developers to define how the authorization check for a CDS entity is executed
@Scope:[#VIEW, #TABLE_FUNCTION]
annotation AccessControl
{
authorizationCheck : String(20) enum { NOT_REQUIRED; NOT_ALLOWED; CHECK;
PRIVILEGED_ONLY; } default #CHECK;
privilegedAssociations: array of AssociationRef;
personalData
{
blocking : String(30) enum { NOT_REQUIRED; REQUIRED;
BLOCKED_DATA_EXCLUDED; BLOCKED_DATA_INCLUDED; };
};
};
Annotation Meaning
Engine Behavior: The runtime and design-time engines handle the authorization check
based on the value of the element.
Values:
Value Description
Engine Behavior: The runtime and design-time engines handle the authorization check
based on the value of the element.
Values:
Value Description
associationRef All associations that are exposed in the projection list and
that are mentioned in the list defined in this annotation
should allow privileged access to the association target. No
DCL check happens at runtime
Engine Behavior: The design-time engines handle the authorization check based on the
value of the element.
Values:
Value Description
Value Description
For a log domain, you specify a business area that the data
element is related to. The business area is necessary be
cause different applications might use the same log domain.
For example, a log domain "account" might be something
different in the Human Resources application than it is in the
Banking application.
Values:
Value Description
NOTE
The value #NOT_REQUIRED is recommended for entities for which no authorization checks are planned yet, but
might be needed by the developer or customer later. To prohibit roles for the entity, use the value
#NOT_ALLOWED.
Examples
Example 1
When the developer activates the following DDL document, since an authorization check isn’t required, ABAP
development tools don’t produce a warning. It doesn’t matter whether a role exists for the entity or not.
At runtime, if there’s a role for entity, then ABAP performs an authorization check with the role. If there’s no
role, there’s no check and no protection for the entity.
Sample Code
@AbapCatalog.sqlViewName: 'DEMO_CDS_PRJCTN'
@AccessControl.authorizationCheck: #NOT_REQUIRED
define view demo_cds_spfli
as select from spfli
{ key spfli.carrid,
key spfli.connid,
spfli.cityfrom,
spfli.cityto }
Example 2
Sample Code
@AbapCatalog.sqlViewName: 'Z_MBB_SQL_SOI'
@AccessControl.authorizationCheck: #NOT_REQUIRED
@AccessControl.personalDataBlocking: #NOT_REQUIRED
@AccessControl.privilegedAssociation: [“tosalesorder”]
define view Z_MBB_CDS_SOI as select from snwd_so_i
association [1] to sacm_cds_snwd_pd as toproduct on product_guid =
prod-uct_id
association [1] to sacm_cds_snwd_so as tosalesorder on parent_key =
sales_id
{
key node_key as salesitem_id,
parent_key,
product_guid,
gross_amount,
tax_amount,
toproduct, --Association
tosalesorder --Association
Example 3
This sample code shows how the annotations for read access logging can be used.
Sample Code
@AbapCatalog.sqlViewName: 'ZBANK_POSTINGS'
@Analytics.dataCategory: #CUBE
@AccessControl.readAccess.logging.output : true
define view Z_BankAccount_Postings
as select from I_GLAccountLineItem
{
AccountingDocument,
PostingDate,
@AccessControl.readAccess.logging.logdomain: { area : 'FINANCE' , domain :
'BANK' }
HouseBankAccount,
@AccessControl.readAccess.logging.logdomain: { area : 'FINANCE' , domain :
'BANK' }
HouseBank,
AmountInTransactionCurrency,
TransactionCurrency
}
Enable the Analytic Manager for multidimensional data consumption, performing data aggregation, and slicing
and dicing data. BI front ends like Design Studio and Analysis Office can consume the data via the Analytic
Manager.
@Scope:[#VIEW]
Annotation Analytics
{
dataCategory : String enum { DIMENSION; FACT; CUBE; AGGREGATIONLEVEL; };
dataExtraction
{
enabled : Boolean default true;
delta :
{
byElement : elementRef;
{
name : RefToElement;
maxDelayInSeconds : Integer default 1800;
detectDeletedRecords: boolean default true;
ignoreDeletionAfterDays : Integer;
};
changeDataCapture
{
automatic : Boolean default true;
mapping
@Scope:[#ELEMENT]
Annotation Analytics
{
internalName : String(30) enum { DEFAULT; LOCAL; GLOBAL; };
};
Usage
The Analytic Manager needs a star schema (multidimensional) and a query to consume the data. Most
annotations to define the star schema in different CDS views are specified in ObjectModel annotations. The
Analytics annotations also specify the facts (center of the star schema), extraction capabilities for
replicating data into further systems, and analytic query properties. A semantic distinction can be made in the
Analytics annotations between annotations that are relevant for the InfoProvider (CUBE) level and
annotations that are only relevant for analytic queries.
Analytics.dataCateg Analytic queries can be defined on top of CDS views using the
ory Analytics.dataCategory annotation.
Scope: #VIEW
Evaluation Runtime (Engine): By specifying the data category, the developer can provide
directives and hints, telling the analytic manager how to interpret individual entities for ex
ample.
Value Description
#DIMENSION This value indicates that the entity represents master data.
This kind of view can be used for replication and for queries.
Example
Typical dimensions are material view and customer view.
#CUBE The #CUBE value (like #FACT) also represents factual data,
but #CUBE does not have to be without redundancy. This
means joins with master data are possible. Queries are usu
ally built on top of #CUBE, where data is replicated from
facts.
#AGGREGATIONLEVEL This value indicates a projection. For this kind of view, the an
alytic manager offers write-back functionality (planning
functionality). Views in this category have to select from a
view with dataCategory = #CUBE, which supports the
annotation Analytics.writeBack.className. No
associations are allowed, and elements cannot be renamed.
Analytics.dataExtra Application developers can use this annotation to mark views that are suitable for data repli
ction.enabled cation (for example, delta capabilities must be provided for mass data).
Scope: #VIEW
Note
This view must be annotated with Analytics.dataCategory (except the value
AGGREGATIONLEVEL) or with ObjectModel.dataCategory with the value
#TEXT or #HIERARACHY .
Value Description
true The view is suitable for data replication. The default is true if
this annotation is used.
Analytics.dataExtra Application developers can enable the generic delta extraction with this annotation. This is
ction.delta.byEleme the element that should be used for filtering during generic delta extraction. This element
nt.name can be either a date (ABAP type DATS) or a UTC time stamp.
Scope: #VIEW
Note
If the field is a time stamp, the system also checks the annotation
Semantics.systemDate.lastChangedAt: true. .
Value Description
elementName as String Name of an element that should be used for filtering during
generic delta extraction.
Analytics.dataExtra There is always a time delay between taking a UTC time stamp and the database commit.
ction.delta.byEleme This annotation specifies the maximum possible delay in seconds.
nt.maxDelayInSecond Scope: #VIEW
s
Evaluation Runtime (Engine):
Value Description
Analytics.dataExtra By using this annotation, the system will remember all key combinations of the view that
ction.delta.byEleme were extracted in delta mode. If a key combination does not occur in the view anymore, this
nt.detectDeletedRec will automatically generate a delete image in the extracted data.
Value Description
Analytics.dataExtra
This annotation only makes sense together with
ction.delta.byEleme
Analytics.dataExtraction.delta.byElement.detectDeletedRecords.
nt.ignoreDeletionAf
The extraction will ignore deleted records if they are older than the specified number of
terDays days. The main purpose is archiving.
Example
If records are archived after two years, this value should be less than 700. In this case,
the deletion in the database tables will be ignored if the record is only older than 700
days.
Scope: #VIEW
Value Description
Analytics.dataExtra Use the CDC (change data capture) delta mechanism based on data base triggers.
ction.delta.changeD
Scope: #VIEW
ataCapture
Evaluation Runtime (Engine):
Analytics.dataExtra In case of simple CDS views like projections no mapping information needs to be provided,
ction.delta.changeD but the relevant information about key fields etc. in inferred by the system.
ataCapture.automati Scope: #VIEW
c
Evaluation Runtime (Engine):
Analytics.dataExtra In case of more complex CDS views, e.g. using joins, mapping information needs to be pro
ction.delta.changeD vided. With this annotation you define the mapping of exposed elements in the CDS view
ataCapture.mapping and the underlying table key fields; see also example 3.
Scope: #VIEW
ction.delta.changeD MAIN The key of the extraction view corresponds exactly to the key
ataCapture.mapping. of the underlying main table to be logged.
role LEFT_OUTER_TO_ONE_J There is a left outer join but not all requirements of role
OIN #COMPOSITION are met.
ction.delta.changeD array of ElementRef List of CDS view elements that map to key fields of the un
ataCapture.mapping. derlying tables.
ction.delta.changeD array of ElementRef List of table key fields that map to CDS view elements.
ataCapture.mapping.
Note
tableElement
Both arrays, viewElement and tableElement,
must contain the same number of elements and must
list them in the same order so that corresponding fields
match. Additionally, the array tableElement must
contain exactly all key elements of the logging table
without the client element.
Value Description
highValue :
String(45);}
Analytics.hidden You can use this flag to decide whether the entity should be visible to analytic clients.
Evaluation Runtime (Engine): Views with Analytics.query are not exposed in value
help. Views with Analytics.dataCategory are not exposed in value help for the CDS
query designer.
Value Description
Analytics.internalN With this annotation, the identifier which is used between BI Tools and the analytic manger
ame can be influenced, meaning that adding @ObjectModel.foreignKey.association
or @ObjectModel.text.association will not change the identifier.
Note
The CDS model is transformed to an InfoProvider or InfoObject model. The analytic pro
tocols like INA or BICS are based on InfoProvider and InfoObject names. The elements
of an analytic CDS view (CUBE, FACT, DIMENSION) are mapped to InfoObject names. If
there is an @ObjectModel.foreignKey.assocation or
@ObjectModel.text.assocation, and the target of the association is only used
once, the InfoObject name is derived by default from the SQL view name of the target
view. These names are called global. The InfoObject name for the representative key
element of a dimension is always derived from the SQL view name of the dimension
view. In all other cases, the InfoObject name is derived from the SQL view name of the
view and the element name. These names are called local.
If multiple elements are used in the ON condition of the foreign key association of an
element, and the InfoObject name should be global, all other elements of the ON condi
tion need to be global InfoObject names. This default behavior can be overruled with
this annotation.
Value Description
Analytics.planning. An input-enabled query provides writeback capabilities and can be used in planning scenar
enabled ios.
Scope: #VIEW
Evaluation Runtime (Engine): Specifies which view will be interpreted as input-enabled an
alytic query by the analytic manager.
Note
This view must be annotated with Analytics.query: true.
Value Description
true The view is enabled for planning. The default is true if this
annotation is used.
Note
The view has to select data from a view, which is anno
tated with Analytics.dataCategory:
#AGGREGATIONLEVEL.
Scope: #VIEW
Evaluation Runtime (Engine): By tagging the CDS view, the developer can specify which
views will be exposed to the analytic manager. This type of view will be interpreted as an
analytic query by the analytic manager.
Note
This view must not be annotated with Analytics.dataCategory = #NONE.
Value Description
true The query view will be exposed to the analytic manager. The
default is true if this annotation is used.
Note
Data will be selected from the view specified in the from
clause. The view of the from clause has to be annotated
with the Analytics.dataCategory as
#DIMENSION, #CUBE or #AGGREGATIONLEVEL, and
the DCL has to be assigned to the view of the from
clause.
false The query view will not be exposed to the analytic manager.
Analytics.settings. If InfoProviders store large amounts of data, certain queries can retrieve large result sets.
maxProcessingEffort The maxProcessingEffort is the maximum effort expected by analytic manager for process
ing the data it retrieves.
Scope: #VIEW
Evaluation Runtime (Engine): This annotation will be interpreted by the analytic manager
for query views (Analytics.query: true).
Value Description
low
medium
unlimited
Analytics.settings. You can specify whether cells that contain zeros as values are to be displayed.
zeroValues.handling
Scope: #VIEW
Evaluation Runtime (Engine): This annotation will be interpreted by the analytic manager
for query views (Analytics.query: true).
Value Description
show You can specify that zeros are to be displayed (No zero sup
pression takes place). The default is show.
hide If you want to suppress zeros, there are two options availa
ble: hide and hide_if_all. For queries that have char
acteristics in the rows and key figures in the columns (or the
other way around, with key figures in the rows and character
istics in the columns), the effect of the settings is identical.
The two settings only differ in how they affect queries that
have characteristics in the rows and columns (cross-classi
fied table). If you use zero suppression with the hide value,
the system checks whether there are zero values in the re
sults area. If there are zero values in the results area, the cor
responding row or column is hidden.
hide_if_all For queries that have characteristics in the rows and key fig-
ures in the columns (or the other way around, with key fig-
ures in the rows and characteristics in the columns), the ef
fect of the value is identical to hide. If your query has char
acteristics in the rows and columns however (cross-classi
fied table), and you use zero suppression with the
hide_if_all value, the system hides all rows or columns
that contain zero values.
Note
If a detail row is not equal to zero (in a hierarchy for ex
ample), all superordinate rows are displayed, even if they
contain zeros. As a result, the system ensures that the
business context of the query is retained for the end
user, even if the value hide_if_all is set.
Analytics.settings. You can specify whether rows or columns that contain zeros as values are to be hidden.
zeroValues.hideOnAx
Scope: #VIEW
is
Evaluation Runtime (Engine): This annotation will be interpreted by the analytic manager
for query views (Analytics.query: true).
Value Description
Evaluation Runtime (Engine): View replication is mainly used for analytical use cases.
Value Description
Scope: #VIEW
Evaluation Runtime (Engine): Specifies which class enables the analytic manager to write
data to the view.
Note
Only relevant if Analytics.dataCategory: #CUBE or
Analytics.dataCategory: #FACT.
Value Description
Examples
Example 1
Sample Code
Example 2
Sample Code
@EndUserText.label: 'EPM Demo: Sales Order Item with Addtl. Data (private
view)'
@Analytics.dataCategory: #CUBE
@ObjectModel.foreignKey.association: '_SalesOrder_E'
key _SalesOrder.SalesOrder,
_SalesOrder_E,
...}
Example 3
Example for defining a list of tables that should be logged for delta data extraction.
Sample Code
@Analytics: {
dataCategory: #FACT,
dataExtraction: {
enabled: true,
delta.changeDataCapture.mapping:
[ { table: 'rsodpcdcunittab2', role: #MAIN, viewElement:
['view_key1', 'view_key2'], tableElement: ['tab_key1', 'tab_key2'] },
{ table: 'rsodpcdcunittab1', role: #LEFT_OUTER_TO_ONE_JOIN,
viewElement: ['view_key3'], tableElement: ['tab_key1'] } ]
} }
Related Information
Enable application developers to specify the default multidimensional layout of the query, the sequence of
variables in UI consumption, and the specific aggregation and planning behavior of the data. All these
annotations can only be used in views with @Analytics.query : true.
@Scope:[#ELEMENT]
Annotation Meaning
AnalyticsDetails.ex Usually, the default aggregation determines how measures are aggregated in analytics.
ceptionAggregationS
teps.exceptionAggre
Caution
gationBehavior The default aggregation behavior cannot be defined in the query. It needs to be defined
on the cube layer.
In some cases different aggregation behavior is needed for a special element of the entity
(dimension of a cube).
Note
Example: A measure "Inventory" can be summed up for the different plants and other
dimensions, but not for time – according to time the last or average value might be rele
vant.
Exception aggregation is optional and is used to define different (to the default aggregation)
aggregation behavior for specified elements. In general there can be multiple elements in
which a measure has to be aggregated differently. Therefore a list of
ExceptionAggregationSteps can be assigned.
ExceptionAggregationBehavior defines the aggregation behavior.
Note
Example: In the query there is a measure, which should show the number of customers
with positive sales - where sales is a measure of the underlying CUBE view with default
aggregation SUM. When the sales measure is now used in a query with
exceptionAggregationBehavior: COUNT and
exceptionAggregationElements : Customer, the sales must first be ag
gregated (SUM) at customer level, and then COUNT has to be performed. If the sales
for a customer is positive, this means that the sales is replaced by 1 (otherwise it is set
to 0). This number can be summed up again.
Scope: #ELEMENT
Evaluation Runtime (Engine): The (logical) order in which the Analytic manager performes
the aggregation is as follows: Firstly the DefaultAggregation is performed. This intermediate
result is still grouped by all elements in the list of ExceptionAggregationSteps. The
result is then aggregated by the exception aggregation in the order of StepNumber.
The first remark holds even if the DefaultAggregation is FORMULA. This means that the cal
culation is performed when the result is still grouped by the exception aggregation ele
ments. After the formula has been calculated, the result is aggregated according to the list
of ExceptionAggregationSteps. This means that the aggregation level to be used
for calculation can be defined precisely.
Value Description
SUM sum
MIN minimum
MAX maximum
NHA NHA
COUNT counter
COUNT_DISTINCT counter_distinct
AVG average
FIRST FIRST
LAST LAST
AnalyticsDetails.ex The elements which should be aggregated in this step. These elements must represent
ceptionAggregationS characteristics.
teps.exceptionAggre Scope: #ELEMENT
gationElements :
Evaluation Runtime (Engine): Analytic manager: For more information see
[ '' ]
AnalyticsDetails.exceptionAggregationSteps.exceptionAggregati
onBehavior.
Value Description
AnalyticsDetails.pl This annotations allows you to define the disaggregation behavior. This annotation is only
anning.disaggregati available for elements with AnalyticsDetails.planning.enabled.
on
Scope: #ELEMENT
Value Description
AnalyticsDetails.pl If disaggregation is chosen, you can choose how the value is distributed during disaggrega
anning.distribution tion with this annotation.
Scope: #ELEMENT
Evaluation Runtime (Engine): This annotation will be ignored if CDS view or the corre
sponding element is not enabled for planning.
Value Description
Scope: #ELEMENT
Evaluation Runtime (Engine): This annotation will be ignored if CDS view or the corre
sponding element is not enabled for planning.
Value Description
AnalyticsDetails.pl Individual members in the selection list (no calculated elements) need to be annotated for
anning.enabled enabling planning. The list can only be used in input-enabled analytic queries. This means
that the views have to be annotated with Analytics.query: true and
Analytics.planning.enabled: true.
Scope: #ELEMENT
Value Description
true The member in the selection list is enabled for planning. This
is the default setting.
false The member in the selection list is not enabled for planning.
AnalyticsDetails.qu The elements of the view can be positioned on multiple axes. The elements can be directly
ery.axis annotated with their axis. Measures (elements which can be aggregated (defaultAggrega
tion)) all need to be on the same axis. The annotation of the first measure will therefore be
used for all measures of the query. If no AnalyticsDetails.query.axis is found,
the system positions the measures on the columns.
The default value for elements which are not measures is the free axis. Note that elements
in the projection list, which belong to the same field in the query, will be grouped together.
Scope: #ELEMENT
Evaluation Runtime (Engine): If the BI client does not specify which elements are on which
axis, the layout is derived by this annotation.
Value Description
ROWS
AnalyticsDetails.qu For measures, restricted measures and calculated elements, you can set the number of dec
ery.decimals imals to be used.
Scope: #ELEMENT
Evaluation Runtime (Engine): Analytic manager: This annotation is only relevant for meas
ures. For other elements it will be ignored.
Value Description
AnalyticsDetails.qu
Scope: #ELEMENT
ery.display
Evaluation Runtime (Engine): Analytic manager
Value Description
AnalyticsDetails.qu This annotation allows you to specify the display hierarchy attribute for the element. It is not
ery.displayHierarch possible for measures.
y Scope: #ELEMENT
Value Description
FILTER The display hierarchy is the same one defined on the filter
for this element. In this case, a hierarchy filter needs to be
defined on the same element. The hierarchy binding is taken
from the filter.
AnalyticsDetails.qu If true, the hierarchy node represented by the annotated entry will be initially collapsed (only
ery.elementHierarch applicable if the annotated entry has children, i.e. is parent of another entry).
y.initiallyCollapse Scope:#ELEMENT
d
Evaluation Runtime (Engine):
Value Description
AnalyticsDetails.qu Measures, restricted measures and calculated elements will be shown as a flat list in the
ery.elementHierarch keyfigure structure of the Analytic Query. To achieve a hierarchical display, select list entries
y.parent can be annotated with
@AnalyticsDetails.query.elementHierarchy.parent and will appear hier
archically below the specified parent entry.
Scope:#ELEMENT
Value Description
elementRef Alias of the select list entry serving as parent for the anno
tated entry.
AnalyticsDetails.qu This annotation allows you to specify the formula expression, which cannot be expressed as
ery.formula an SQL formula (operands required from the element list of the view). Only numerical values
(measures) can be used as operands.
Scope: #ELEMENT
Value Description
● cube measures
● arithmetic expressions
● functions NDIV0 and NODIM
● CASE expressions with a maximum of one THEN clause
(will be translated into BW IF operator)
○ WHEN clause can contain conditional or Boolean
expressions of measures
○ ELSE clause is optional (default to ELSE 0 )
AnalyticsDetails.qu
Scope: #ELEMENT
ery.hidden
Evaluation Runtime (Engine): Analytic manager:
Scope: #ELEMENT
Value Description
#CONSTANT Constant
AnalyticsDetails.qu This annotation contains, depending on the type, a literal value, the parameter name (with
ery.hierarchyBindin out : or $parameter), the element name and an identifier for the user input field, respec
g.value tively.
Scope: #ELEMENT
Value Description
String(512)
AnalyticsDetails.qu This annotation defines which hiearchy level will be displayed initially.
ery.hierarchyInitia
Scope: #ELEMENT
lLevel
Evaluation Runtime (Engine): Analytic manager:
Value Description
Integer: Integer number Hierarchy level with that number will be displayed initially.
AnalyticsDetails.qu This annotation allows you to specify the order of parameters and variables on the variable
ery.hierarchyBindin input UIs.
g.variableSequence
Note
You can also use the annotation
Consumption.filter.hierarchyBinding.variableSequence.
In case filters or parameters are not annotated they are displayed after the annotated ones
in the order they appear in the CDS document.
Scope: #ELEMENT
Value Description
AnalyticsDetails.qu For some hierarchies (typical example: CostCenter hierarchy), the hierarchy nodes can have
ery.hierarchySettin posted values on their own (and not just represent the aggregation over all it's child nodes)
gs.hidePostedNodesV which are displayed as separate rows in the report. Using this annotation the display of the
Scope: #ELEMENT
Value Description
AnalyticsDetails.qu For measures, restricted measures and calculated elements, you can set the scaling factor
ery.scaling to be used.
Scope: #ELEMENT
Evaluation Runtime (Engine): This annotation is only relevant for measures. For other ele
ments it will be ignored.
Value Description
AnalyticsDetails.qu
Scope: #ELEMENT
ery.sortDirection
Evaluation Runtime (Engine): Analytic manager:
AnalyticsDetails.qu For attributes you can set the behavior for totals.
ery.totals
Scope: #ELEMENT
Value Description
HIDE Totals or subtotals are not added to the result set for this el
ement.
SHOW In addition to the details, the subtotals are added to the re
sult set for this element.
AnalyticsDetails.qu If user input is necesssary for the parameter, the sequence of all fields for user input at run
ery.variableSequenc time can be specified with this annotation.
e Scope: #PARAMETER, #ELEMENT
Evaluation Runtime (Engine): UIs will create user prompts for parameters which require a
user input or elements with filters (consumption.filter). This annotation can be used to
specify the sequence of user prompts at runtime. If filters or parameters are not annotated,
they are displayed after the annotated ones - in the order they appear in the CDS document.
Value Description
AnalyticsDetails.re This annotation influences the list of values, which should be taken into account for a spe
sultValueSource cific characteristic.
Scope: #ELEMENT
Evaluation Runtime (Engine): When the query is executed, a row of data is only displayed
for the characteristic if there are posted values for this characteristic.
Value Description
Examples
Example 1
Calculated Elements
Sample Code
@Analytics.query : true
define view fincancial as select from sales
{
@AnalyticsDetails.query.axis : #ROWS
product,
@AnalyticsDetails.query.axis : #COLUMNS
@AnalyticsDetails.query.formula : 'revenue - cost'
1 as absolute_margin,
@AnalyticsDetails.query.formula : 'NDIV0($projection.absolute_margin /
revenue ) * 100'
1 as relative_margin,
Example 2
Sample Code
@Analytics.query : true
define view costcenter_reporting
with parameters
cost_center_hier_param : String
as select from costcenters
{
...
@AnalyticsDetails.query : {
displayHierarchy: #ON,
Example 3
The system supports variables like $session.system_date for different use cases:
● in cube parameters
Sample Code
@Analytics.query : true
define view …
as select from zCostCenter_Flt( P_KeyDate: $session.system_date )
Sample Code
} where
DateTo >= $session.system_date and
DateFrom <= $session.system_date
Sample Code
Related Information
Define a specific behavior that relates to the consumption of CDS content through domain-specific
frameworks.
@Scope:[#ELEMENT, #PARAMETER]
Annotation Consumption
{
labelElement : elementRef;
quickInfoElement : ElementRef;
hidden : Boolean default true;
derivation
{
lookupEntity : entityRef;
pfcgMapping : String(30);
resultElement : elementRef;
resultElementHigh : elementRef;
resultHierarchyNode
{
nodeTypeElement : ElementRef;
mapping : array of
{
hierarchyElement : ElementRef;
lookupElement : ElementRef;
};
};
binding : array of
{
targetParameter : parameterRef;
targetElement : elementRef;
type : String(10) enum { ELEMENT; PARAMETER; CONSTANT; SYTEM_FIELD };
};
label : String(60);
presentationVariantQualifier : String(120);
};
@Scope: [#VIEW]
Annotation.Consumption
{
dbHints : array of String(1298);
dbHintsCalculatedBy : String(255);
}
Usage
Via these annotations, the specific behavior is defined which is related to the consumption of CDS content.
This metadata makes no assumptions about the concrete consumption technology/infrastructure, but it is
applicable across multiple consumption technologies (e.g. Analytics or OData).
Annotation Meaning
Values:
Note
The defaultValue annotation is only allowed
for View parameters. Elements and default val
ues can only be specified within filters. Hence, the
annotation
@Consumption.filter.defaultValue
has to be used.
Note
Analytic manager: Annotation of a non-filtered
element of the projection list with a derivation is
not allowed.
Value Description
elementRef
Value Description
parameterRef
Value Description
#ELEMENT
#PARAMETER
#CONSTANT
Note
Analytic manager: If parameter values are used
in this sub-annotation, the corresponding param
eter must be declared before the parameter that
is to be derived. For SADL the order does not
matter.
Note
Analytic manager: All provided annotation values
are treated case sensitive.
Value Description
Values: Description
entityRef
Note
If this annotation is used for a parameter, then
with
Consumption.derivation.resultElem
ent the field has to be specified, from which the
distinct values should be selected. Only fields can
be used, which belong to the key of the hierarchy.
It can be used, if the hierarchy should also be de
rived from the PFCG-mapping. The parameter
has to be used in the
Consumption.filter.hierarchyBindi
ng annotation.
Values: Description
Values: Description
elementRef
Values: Description
elementRef
Example
1000/4711 is a costcenter which has further
costcenters as children.
Example
If the selected record from the lookup entity is
equal to (nodeTypeElement, controllingArea,
costCenter) = (space, 1000, 4711) means always
the leaf. While (costCenter, 1000, 4711) means
the node. If this does not exist, then it is inter
preted as a leaf.
Values: Description
Caution
Consumption.
filter.defau
ltHierarchyN
ode.nodeType
is an element
name which de
scribes the node
type.
hierarchyElement :
elementRef
lookupElement:
elementRef
Scope: #ELEMENT
Note
This element should be exposed by UIs. UIs
based on Analytic Manager will offer this element
as variables.
Value Description
Value Description
Consumption.filter.defaultHierarchyNode.nodeT Consumption.filter.defaultHierarchyN
ype
ode can only be used in combination with
Consumption.filter.selectionType =
#HIERARCHY_NODE.
In
Consumption.filter.hierarchyBinding,
the hierarchy is specified
Value Description
elementRef
element :
elementRef
Value Description
Default: true
Value Description
#CONSTANT Constant
Value Description
String(512)
Note
You can also use the annotation
AnalyticsDetails.query.hierarchyB
inding.variableSequence.
Value Description
Example
The user deletes the proposal for a mandatory fil-
ter in the Filter UI. The UI then displays an error
message "Please enter a value for filter ...". After
the user has entered a value , the entered value is
then sent to the engine. Therefore, the Filter UI
ensures that automatic replacement by the en
gine is never performed for mandatory filters.
Value Description
Boolean (true,
false)
Value Description
selectionType IN list
SINGLE and
multipleSelections
= true
Value Description
Scope: #ELEMENT
Note
Whenever such elements are used for querying
grouped data, the context-providing elements
should also be included in the query's "group by"
expression.
Value Description
elementRef
Note
The field will not be exposed to UIs.
Value Description
Default: true
Note
We recommend to use
ObjectModel.text.element[ ] instead
of the Consumption.labelElement anno
tation.
Value Description
elementRef
Example
SAP Fiori has introduced the concept of intent-
based navigation, whereby an intent is a combi
nation of <semanticObject> <action>. A
semanticObject annotation is used in SAP
Fiori UIs to dynamically derive navigation targets
for the annotated view as a source.
Value Description
Value Description
elementRef
Value Description
Consumption.valueHelpDefinition.distinctValue Specifies whether the value help result list shall only
s contain distinct values for the annotated field or pa
rameter. If set to true all mappings will be used for fil-
tering, but only the value for the field/parameter
which the value help was requested for will be re
turned by the value help.
Consumption.valueHelpDefinition.entity[] Defines the binding for the value help to the value help
providing entity. It requires specification of the entity
and the element providing the value help for the anno
tated element.
Value Description
Example 1
Sample Code
@Consumption.labelElement: 'CompanyName'
@Consumption.quickInfoElement: 'CompanyDescription'
so.buyer_guid AS BuyerGuid,
so.company_name AS CompanyName,
so.description AS CompanyDescription
}
Example 2
The annotation Consumption.groupWithElement is used to define that the element CompanyName depends
semantically on the element BuyerGuid. In the case of an aggregated table, the fields can be displayed
combined:
Sample Code
so.buyer_guid AS BuyerGuid,
@Consumption.groupWithElement: 'BuyerGuid'
so.company_name AS CompanyName,
so.currency_code AS CurrencyCode,
@DefaultAggregation: #SUM
so.gross_amount AS GrossAmount
}
Example 3
The annotation Consumption.hidden is used to prevent fields from being exposed by OData. The annotation,
therefore, prevents fields from being available to the client. This is necessary for system parameters because
these parameters need to be filled by the runtime-engine, but must not be available to the client:
Sample Code
@Consumption.hidden: true
so.buyer_guid AS BuyerGuid,
_Customer.company_name AS CompanyName
}
Example 4
The annotation Consumption.defaultValue is used to specify default values for parameters. In this
example, the currency EUR is used:
Sample Code
$parameters.p_TargetCurrency AS CurrencyCode,
currency_conversion(
amount => so.gross_amount,
source_currency => so.currency_code,
target_currency => $parameters.p_TargetCurrency,
exchange_rate_date => CAST( '20150101' AS abap.dats )
) AS GrossAmount
}
Example 5
The annotation Consumption.valueHelp is used to expose an association as a value help. In this example,
the CDS view CurrencyCodeValueHelp is used for the field CurrencyCode:
The annotation Consumption.valueHelpDefinition is used to define a value help for the annotated
element. The value help provider can be a different CDS entity without association. To consume the value help,
the value help provider entity must be added to the respective OData service.
You can filter the available value help options by defining an additional binding. In the following example case,
only the business partners are displayed that use the same currency code.
Sample Code
element : 'CurrencyCode'
}]
}]
_BusinessPartner.BusinessPartnerID
Example 6
Sample Code
@Consumption.semanticObject: 'SalesOrder'
DEFINE VIEW SalesOrder
AS SELECT FROM sepm_cds_sales_order AS so
{
so.sales_order_id AS SalesOrderId,
@Consumption.semanticObject: 'BusinessPartner'
so.buyer_guid AS BuyerGuid,
}
Example 7
The annotation Consumption.filter is used to enable filters for values. In this example,
product_hierarchy is filtered for several single values of calendar_day, and for one single interval of
product.
Sample Code
@Analytics.query : true
DEFINE VIEW product_hierarchy
AS SELECT FROM sales
{
...
@Consumption.filter : { selectionType : #SINGLE, multipleSelections :
true}
calendar_day, //several single values are allowed
@Consumption.filter : { selectionType : #INTERVAL, multipleSelections :
false }
product, // single interval allowed
...
}
Example 8
The annotation Consumption.filter is used to enable filters for values. In this example,
costcenter_reporting is filtered hierarchically for the constant CONTR_AREA_10 and for the parameter
cost_center_hier_param.
Sample Code
@Analytics.query : true
DEFINE VIEW costcenter_reporting
with parameters cost_center_hier_param : String
AS SELECT FROM costcenters
{
...
costs,
...
}
Example 9
This example shows how to specify hierarchy nodes as default value in the Consumption.filter annotation.
A consumption view should provide a prompt for a hierarchy node of a costcenter hierarchy with default
1000/ALL (HierarchyNode).
Sample Code
Example 10
This example shows how to enable the Consumption.derivation annotation to return hierarchy nodes. The
annotation Consumption.derivation.resultHierarchyNode is used to return hierarchy nodes. Given a
view CostcenterResponsible with fields field1, field2, field3, field4, and responsible. The query view should
filter by the costcenter nodes the given responsible (parameter) is responsible for.
Sample Code
Example 11
Sample Code
// Analytic Query
@Analytics.query: true
define view ...
with parameters
@Consumption.derivation: { pfcgMapping: 'I_PROFITCENTERHIERAUTH' ,
resultElement: 'ProfitCenterHierarchy' }
P_ProfitCenterHierarchy : fis_hryid_prctr,
@Scope:[#ELEMENT]
annotation Aggregation
{
default: String(30) enum
{
Usage
With this annotation, you can specify the aggregation behaviour of elements in generic usage like analytic
manager or ODATA. Elements without default aggregation or with Aggregation.default: #NONE will not be
aggregated and will be used in GROUP BY for aggregating access. Elements that can be aggregated are known
as measures.
Annotation Meaning
Evaluation Runtime (Engine): This annotation will be interpreted by the analytic manager.
Use all values for this anntotation only for fields of numeric type. Exception is NONE: It has
to be used for all strings like elements.
Values:
Value Description
SUM The total (sum) of all values in this column is shown in the
result line.
Note
The analytic manager allows AVG only together with
Aggregation.referenceElement and exactly
one element in this list. Aggregation:
{ default: #AVG , referenceElement:
<element> } behaves like Aggregation:
{ default: #SUM, exception: #AVG ,
referenceElement: <element> }.
Note
The analytic manager allows COUNT only together with
Aggregation.referenceElement and exactly
one element in this list. Aggregation:
{ default: #COUNT , referenceElement:
<element> } behaves like Aggregation:
{ default: #SUM, exception:
#COUNT_DISTINCT , referenceElement:
<element> }.
Note
The analytic manager allows COUNT_DISTINCT only
together with Aggregation.referenceElement
and exactly one element in this list. Aggregation:
{ default: #COUNT_DISTINCT ,
referenceElement: <element> } behaves like
Aggregation: { default: #SUM,
exception: #COUNT_DISTINCT ,
referenceElement: <element> }.
Note
This can only be used in views with
Analytics.query: true.
Example
Margin : = Revenue / Cost. If Margin should be shown
per OrgUnit in a report, the aggregates of Revenue and
Cost have to be determined per OrgUnit first, and then
the Margin has to be calculated per OrgUnit.
NONE This value indicates that the element is not a measure. Usu
ally these elements are used in filters and GROUP BY state
ments.
Aggregation.excepti Exception aggregation is always performed in addition to default aggregation, which must
on not be be equal to #NONE. This is not an alternative to default aggregation. This means that
data is first aggregated through the default aggregation grouped by the reference elements,
and then aggregated with the exception aggregation.
Note
If you want to use Aggregation.exception, you have to define
Aggregation.default (not equal to NONE) and
Aggregation.referenceElement in order to define the granularity with which
the aggregation rule is applied.
Scope: [ELEMENT]
Evaluation Runtime (Engine): This annotation will be interpreted by the analytic manager.
Values:
Value Description
SUM, MAX, MIN, AVG, All these values determine the aggregation of the measure in
COUNT, the same way as SUM, MAX, MIN, AVG, COUNT,
COUNT_DISTINCT COUNT_DISTINCT in Aggregation.default.
FIRST, LAST These values indicate that the first or last value in relation to
the reference characteristic is shown in the result line.
STANDARD_DEVIATION This value indicates that, after aggregating with the refer
ence characteristic, the standard deviation of the calculated
values is shown in the results row.
VARIANCE This value indicates that, after aggregating with the refer
ence characteristic, the variance of the calculated values is
shown in the results row.
MEDIAN This value indicates that the middle value (central value) of a
set sorted in ascending order is calculated:
Example
For a set of five elements, the result is the value of
the third element. Suppose you have the following
values: 1, 12, 2, 4, 24. When the values are sorted in
ascending order (1, 2, 4, 12, 24), the median is the
third middle value, which is 4.
Example
For a set of six elements, the result is the average of
the third and fourth elements. Suppose you have
the following values: 1, 12, 2, 4, 24, 6. When the val
ues are sorted in ascending order (1, 2, 4, 6, 12, 24),
the median is the average of the values 4 and 6,
which is 5.
Aggregation.referen In views of dataCategory: #CUBE or #DIMENSION you can use exactly one ele
ment. In analytic queries (Analytics.query: true) you can use up to five elements.
ceElement
The elements in the list cannot be measures.
Scope: [ELEMENT]
Evaluation Runtime (Engine): This annotation will be interpreted by the analytic manager.
Value Description
Examples
Sample Code
@Semantics.currencyCode:true
GlobalCurrency,
@Aggregation.default: #SUM
@Semantics: { amount : {currencyCode: 'GlobalCurrency'} }
FixedAmountInGlobalCrcy,
Sample Code
calendarDay,
@Semantics.unitOfMeasure: true
unit,
@Aggregation.default: #SUM
@Aggregation.exception: #LAST
@Aggrgation.referenceElement: ‘calenderDay’
@Semantics.quantity : ‘unit'
Quantity
This view describes the quantity of certain goods in a stock per calendar day. The measure quantity can be
aggregated with SUM for all dimensions except the calendar day.
Non-aggregated data
calendarDay Plant Material Quantity
Material1 01/01/2018 40 PC
Material1 02/01/2018 30 PC
Material1 Result 30 PC
Material2 01/01/2018 90 PC
Example 3: Counter-optimized
For CDS views representing master data reports (the FROM clause refers to a CDS view categorized as
#DIMENSION), a counter of the different dimension values can be defined by combining the annotation
Aggregation: #SUM with a select list entry containing constant value 1:
Sample Code
With costCenter in the key of the dimension, no exception aggregation is involved, thus improving the
performance of the report.
Note
This pattern can be combined with CAST statements (for reusing texts of DDIC data types) and/or CASE
statements (for defining restricted measures). You must not use other constants than 1 however, or add
annotation AnalytcisDetails.query.formula.
Related Information
Note
These annotations are currently only available for SAP-internal projects and not released for customer
projects.
Note that SAP might change the behavior of this annotation in future. Consequently, functionality might
change. Therefore, usage is on your own responsibility for customer projects. SAP recommends not to use
these CDS annotations in customer projects.
Usage
Annotation Meaning
EnterpriseSearch.en Defines if a CDS view is generally relevant for search scenarios based on SAP HANA Enter
abled prise Search.
Note
EnterpriseSearch annotations require the annotation @Search.searchable
for the same view.
Scope: #View
Values:
Value Description
Boolean (true, false) Defines whether a CDS view is relevant for Enterprise Search
or not. If it is set to true a search connector is created in En
terprise Search automatically.
Default: true
EnterpriseSearch.fi Specifies that the element is to be considered as a request field which is used for facetted
lteringFacet search (also named interactive navigation or guided navigation).
Scope: #Element
Values:
Value Description
Default: { default }
EnterpriseSearch.de Specifies that the element is to be considered for suggestions (also named type-ahead or
faultValueSuggestEl auto-completion function).
ement
Scope: #Element
Values:
Value Description
Boolean (true, false) Defines weather the element is to be considered for sugges
tions.
Default: true
Related Information
Enables an application developer to specify a parent-child hierarchy that s/he wants to make explicitly
accessible in a data model, together with the structure that defines this hierarchy.
@Scope:[#VIEW]
Annotation Hierarchy
{
parentChild : array of
Usage
The parent-child hierarchy is based directly on the master data entities. The hierarchy is time-dependent if the
master data entity is as well. The hierarchy is defined either by one parent element (with
Hierarchy.parentChild.recurseBy) or by multiple parents (with Hierarchy.parentChild.recurse).
A parent element describes a self-referencing relationship within the master data entity and will usually be
defined via an association. Only one level needs to be assigned to a parent-child hierarchy, because the levels in
the hierarchy are taken from the parent-child relationships between members associated with the parent
element. One or more parent-child hierarchies can be defined within the same master data entity.
Note
A simple example of a parent-child hierarchy is the “Employee” master data. A “Manager” is an “Employee”
and almost every “Employee” is assigned to a “Manager”.
Hierarchy.parentChild.director For external hierarchies, the view of hierarchy nodes often contains the no
y des for multiple alternative hierarchies. A user is supposed to choose a sin
gle hierarchy for display, and his/her selection is used as a filter when se
lecting from the hierarchy node view. The directory annotation identi
fies an association, the hierarchy directory association, from the hierarchy
node view to a view (the so-called hierarchy directory), providing all availa
ble alternative hierarchies for this hierarchy node view.
Scope: #VIEW
Value Description
Scope: #VIEW
Values (optional):
Value Description
Caution
We need to distinguish the above use case from the following one: In a
time hierarchy YEAR, QUARTER, MONTH January under 2011 and Jan
uary under 2012 are not the same member with multiple parents. They
are different Januaries.
Scope: #VIEW
Value Description
Hierarchy.parentChild.name Technical name of the hierarchy. Only relevant if the view defines one hier
archy only, and Hierarchy.parentChild.directory is not used.
Scope: #VIEW
Value Description
Hierarchy.parentChild.orphaned Defines how nodes without a parent (more precisely with a parent that does
Node.handling not occur as a child) are processed.
Scope: #VIEW
Value Description
Hierarchy.parentChild.orphaned Defines how nodes without a parent (more precisely with a parent that does
Node.stepParentNodeId not occur as a child) are processed.
Scope: #VIEW
Value Description
Hierarchy.parentChild.recurse. If the underlying view definition does not contain an association defining
child the parent-child relationship but only “normal” elements, this annotation
has to be used to define the children.
Scope: #VIEW
Value Description
Hierarchy.parentChild.recurse. If the underlying view definition does not contain an association defining
parent the parent-child relationship but only “normal” elements, this annotation
has to be used to define the parents.
Scope: #VIEW
Value Description
array of The element names define the key elements of the “pa
elementRef; rent”.
Scope: #VIEW
Value Description
Hierarchy.parentChild.rootNode Using this annotation, you can define dedicated metadata for how to handle
.visibility root node(s) in the hierarchy.
Scope: #VIEW
Value Description
ADD_ROOT_NOD The system will add the root node of the hierarchy if it
E_IF_DEFINED is explicitly defined, but the system will not add an ex
tra artificial root node. This is the default.
ADD_ROOT_NOD The system will always add an artificial single root node
E to the hierarchy. All other nodes are descendants of
this node.
DO_NOT_ADD_R The system will not add an artificial single root node to
OOT_NODE the hierarchy.
Scope: #VIEW
Value Description
Hierarchy.parentChild.siblingsOrder.direction defines
if the sort order of values with the same parent is “ascending” or “descend
ing”.
Scope: #VIEW
Value Description
Examples
Example 1
Sample Code
Example 2
Sample Code
Example 3
Sample Code
Provide definitions of structural as well as transactional related aspects of the business data model
@Scope:[#VIEW]
Annotation ObjectModel
{
lifecycle {
processor:
{
expiryBehavior : String(30) enum { RELATIVE_TO_PROCESSING_START;
RELATIVE_TO_LAST_CHANGE; } default #RELATIVE_TO_LAST_CHANGE;
expiryInterval : String(20) default ‘PT15M’;
notificationBeforeExpiryInterval : String(20) default ‘PT5M’;
};
enqueue
{
Usage
Annotation Meaning
ObjectModel. Defines the association type that is used for defining a compositional view hierarchy.
association.
Scope: [ELEMENT]
type[ ]
Evaluation Runtime (Engine):
● SADL: Influences the scope of the OData auto-exposure (@OData.publish:true): All views
that are included in the view hierarchy are automatically included in the same OData V2-service.
● BOPF: Influences the scope of the BOPF Business Object generation
(@ObjectModel.transactionalProcessingEnabled : true): All views that are in
cluded in the view hierarchy are automatically included in the same BOPF business object.
Values:
Value Description
#TO_COMPOSIT Views that do not represent the root of the hierarchy must have an association to
ION_PARENT their compositional parent view annotated with
#TO_COMPOSITION_PARENT.
#TO_COMPOSIT Additionally, views that do not represent the root must have a
ION_ROOT #TO_COMPOSITION_ROOT association for performance reasons (for example:
authorization checks (instance restrictions) based of information from root
views).
NOTE: In such a case, the root view of the hierarchy must be annotated with
@ObjectModel.compositionRoot: true .
ObjectModel. If this annotation has value true, it is allowed to create new instances.
createEnable
Scope: [VIEW]
d
Evaluation Runtime (Engine):
ObjectModel. Defines the category of data that is represented by the below-mentioned values.
dataCategory
Scope: [VIEW]
Evaluation Runtime (Engine): In ABQL joins between a Data- and a Text entity without explicit lan
guage key handling will be interpreted as a 1 : (0,1) association, where the language key is defaulted
with the logon language.
Values:
Value Description
#TEXT Indicates that the annotated entity represents texts. Usually one key element is of
type language.
#HIERARCHY Indicates that the entity represents the hierarchy-related data. This could be a
header information or structure information.
ObjectModel. If this annotation has value true, it is allowed to delete existing instances.
deleteEnable
d Scope: [VIEW]
ObjectModel. If this annotation has the value true, the corresponding element (field or association) is supported at
enabled
runtime.
Scope: [ELEMENT]
ObjectModel. This annotation is related to a single field that contains the change state of an active instance of an
entityChange business object. The change state is always updated as soon as the instance data is changed. Usually,
StateId
fields like last changed timestamp, hash values, or version counters are used as
EntityChangeStateIds.
With the value 'EXTERNAL_CALCULATION', the change state of a business object instance is calcu
lated in BOPF. You can use this value if the underlying table does not provide any field that is applicable
as an entity tag (ETag). BOPF calculates the hash value form the entire business object. This calcula
tion can be used as an indicator for changes concerning the state of the related instances. Consider
however that this calculation might have a negative effect on the performance.
Scope: [VIEW]
ObjectModel. Defines association to a view that represents a value list/check table of the annotated filed. The anno
foreignKey.a tated field must be valuated as equal to the annotated representative key field of the target view. The
ssociation maximum target cardinality of the association has to be 1.
Scope: [ELEMENT]
● Analytic Manager: Uses associated view as DIMENSION view for the annotated field.
● SADL: Derives a default value help support from the foreign key relationship.
ObjectModel. This annotation can be added to the key field that specifies the association to a hierarchy view. The
hierarchy view defines an external hierarchy for the instances of the current view and is annotated with
hierarchy.as
@ObjectModel.dataCategory: #HIERARCHY.
sociation
Scope: [ELEMENT]
ObjectModel. The assignment of a processor to a shared draft related causes an exclusive lock for editing the draft
lifecycle.pr document. The lifecycle.processor. annotations allow to overrule the global defaults for the
ocessor.expi
processor expiration handling. After a certain period of time, the exclusive lock on the draft document
ryBehavior
has to be released. This period of time is defined by the specified expiry behavior.
● RELATIVE_TO_ENQUEUE_START: The period of time starts when the processor has been ini
tially assigned.
● RELATIVE_TO_LAST_CHANGE: The interval RELATIVE_TO_LAST_CHANGE describes the
period of inactivity (no modifying roundtrips to the draft document), after that the processor has
to be removed.
Scope: [VIEW]
ObjectModel. To notify the draft processor in advance before the expiration takes place, a notification will be send.
lifecycle.pr The default warning interval can be overruled by the help of annotation
ocessor.noti
notificationBeforeExpiryInterval. The value must be compliant to the dayTimeDuration
ficationBefo
format .
reExpiryInte
rval Scope: [VIEW]
ObjectModel. The creation of an exclusive draft related to an existing active document causes an exclusive durable
lifecle.enqu lock of the active document. The lifecycle.enqueue.* annotations allow to overrule the global
eue.expiryBe
defaults for the durable lock expiration handling. After a certain period of time, the durable exclusive
havior
lock on the active document has to be released. This period of time is defined by the expiration behav
ior.
● RELATIVE_TO_ENQUEUE_START - The period of time starts from the point in time the exclu
sive durable lock has been initially acquired.
● RELATIVE_TO_LAST_CHANGE - The interval describes the period of inactivity (no modifying
roundtrips to the draft document), after that the exclusive durable lock has to be removed
Scope: [VIEW]
Evaluation Runtime (Engine): The lifecycle services automatically unlock active documents accord
ingly to the defined enqueue expiration behavior.
ObjectModel. Using this annotation, you can specify an interval to overrule the default duration.
lifecle.enqu
The value must be compliant to the dayTimeDuration format (http://www.w3.org/TR/
eue.expiryIn
xmlschema11-2/#dayTimeDuration).
terval
Scope: [VIEW]
ObjectModel. To notify the draft processor in advance before the expiration takes place, a notification will be send.
lifecle.enqu The default warning interval can be overruled by the help of annotation
eue.notifica notificationBeforeExpiryInterval using the valid dayTimeDuration format (http://
tionBeforeEx www.w3.org/TR/xmlschema11-2/#dayTimeDuration).
piryInterval
Scope: [VIEW]
ObjectModel. After the durable lock expiration phase has been processed for an exclusive draft, the durable lock of
lifecle.proc its active document is released. However for draft-aware applications it is still not allowed to create a
essing.expir
new draft related to the same active document until the processing of the existing draft is expired.
yBehavior
The lifecycle.processing.* annotations allow to overrule the global defaults for the draft
processing expiration handling. After a certain period of time, the processor is removed from an exclu
sive draft and a different user is allowed to create a new draft related to the same active document. In
that case, the first draft is deleted. Otherwise, the editing for the first draft can be continued at a later
point in time.
The default processing expiration settings can be overruled like the lifecycle.enqueue.* anno
tations by the help of a behavior, duration interval and notification interval.
Scope: [VIEW]
Evaluation Runtime (Engine): The lifecycle services automatically set the processing status of a draft
accordingly to the defined processing expiration behavior.
ObjectModel. Using this annotation, you can specify an interval to overrule the default duration interval.
lifecle.proc
essing.expir Scope: [VIEW]
yInterval
ObjectModel. Using this annotation, you can specify an interval to overrule the default notification interval.
lifecle.proc
essing.notif Scope: [VIEW]
icationBefor
eExpiryInter
val
ObjectModel. To comply to data privacy policies and the deletion of personal data, drafts have to be deleted after a
lifecycle.dr certain period if they are not processed any more. The default expiration timeframe is 28 days. The
aft.expiryBe
lifecycle.draft. annotations allow to overrule the global defaults for the draft expiration han
havior
dling. After a certain period of time, the draft document has to be deleted. This period of time is de
fined by the expiry behavior.
● RELATIVE_TO_ENQUEUE_START : The period of time starts from the point in time the draft
document has been initially created.
● RELATIVE_TO_LAST_CHANGE : The interval describes the period of inactivity (no modifying
roundtrips to the draft document), after that the draft document has to be removed.
Scope: [VIEW]
ObjectModel. Using this annotation, you can overrule the default duration. The value must be compliant to the dayTi
lifecycle.dr
meDuration format .
aft.expiryIn
terval Scope: [VIEW]
ObjectModel. To notify the draft processor in advance before the expiration takes place, a notification will be send.
lifecycle.dr The default warning interval can be overruled using this annotation. The value must be compliant to
aft.notifica
the dayTimeDuration format .
tionBeforeEx
piryInterval Scope: [VIEW]
With the value 'EXTERNAL_CALCULATION', you have the option to specify on which conditions the
element is defined as mandatory (dynamic field control). The mandatory property is in this case calcu
lated in a property determination of the corresponding business object’s node.
Scope: [ELEMENT]
ObjectModel. Each business object can semantically be categorized using this object model setting
modelCategor
Scope: [VIEW]
y
Evaluation Runtime (Engine): The model category must not have any runtime effect but is used for a
semantic grouping, for example in view browsers.
Values:
Value Description
ObjectModel. If this annotation has the value true, the field must not be updated by the consumer.
readOnly
Scope: [ELEMENT]
ObjectModel. Most specific element (field or managed association) of the primary key (indicated by the keyword
representati KEY) that represents the entity which the view is based on. This element shall be used as the anchor
veKey for defining foreign key relationships (except for text views): The foreign key field corresponding to the
representative key represents the entity. As such it can be called representative foreign key element.
The foreign key association is defined on the representative foreign key element. The name of the rep
resentative key typically equals the name of the entity represented by the view.
For non-text views it is the key element for which the view serves as a value list/check table. For text
views (@ObjectModel.dataCategory: #TEXT) it identifies the key element to which the text
fields relate to.
The representative key element has to be modelled explicitly even if there is only one primary key field
(no implicit derivation).
A view may only become a target of a foreign key association if it has a representative key element
(exception: language dependent text views may not be used as targets of foreign key relationships)
Scope: [VIEW]
Evaluation Runtime (Engine): Analytic Manager: In analytics, both the grouping by the entity and the
hierarchical representation of the entity are handled using the representative foreign key field.
ObjectModel. Identifies an instance of an entity from business perspective using human-readable field values. It
semanticKey[ does neither contain time-/language-dependent nor other technical components (for example: draft
] indicator). Thus it may be ambiguous resulting in multiple selected records/instances of a view that
may need to be filtered using contextual information (for example: current date, preferred language).
Scope: [VIEW]
Evaluation Runtime (Engine): UI: Uses semantic key for bookmarking and navigation.
ObjectModel. Defines the associated view (annotated with @ObjectModel.dataCategory: #TEXT), which
text.associa
provides textual descriptions for the annotated field.
tion
NOTE: The usage of this annotation excludes the usage of @ObjectModel.text.element.
Scope: [ELEMENT]
● SADL - Enriches the OData entity type of the view with the textual description of the target view
applying an automated language filtering. The name of the auto-generated text property will be
composed out of the annotated field name and the constant suffix _Text. This OData property is
mapped onto the first text field of the associated target CDS view annotated with
@Semantics.text:true.
● Analytic Manager - Uses the associated view as TEXT view for annotated field.
ObjectModel. Establishes the conjunction of a field with its descriptive language-independent texts.
text.elemen NOTE: The usage of this annotation excludes the usage of @ObjectModel.text.association.
t[ ]
Scope: [ELEMENT]
Evaluation Runtime (Engine): SADL - First text field listed in the annotation array will be handled as
descriptive text of the annotated field in OData exposure scenarios.
ObjectModel. Indicates that transactional accesses to the view are delegated to the transactional runtime of the un
transactiona derlying view (which is annotated with
lProcessingD
@ObjectModel.transactionalProcessingEnabled:true). It may only be defined on
elegated
root view level (@ObjectModel.compositionRoot:true).
Scope: [VIEW]
ObjectModel. If this annotation has value true, it is allowed to update existing instances.
updateEnable
d Scope: [VIEW]
ObjectModel. The size category enables the consumer of a service to estimate the possible results set. It reflects the
usageType.si set of data that has to be searched through to compute, for example, the number of rows in the results
zeCategory
set by using a count(*) function in a CDS view.
You can assign one of the following size categories, which specifies the expected number of data sets
(rows) in a production customer system:
S: < 1000
M: < 100.000
L: < 10.000.000
Scope: [VIEW]
ObjectModel. This annotation reflects the quality of the service that results from the CDS view. Using this annota
usageType.se tion, the consumer is able to decide whether or not the annotated CDS view fits the demanded re
rviceQuality
sponse time and the throughput requirements.
Each CDS view can be assigned to one of the following quality categories:
A: The annotated CDS view may be consumed within the business logic for high volume transactions
or in background processing.
B: The annotated CDS view may be consumed within business logic for transactions or in background
processing.
C: The annotated CDS view may be consumed from the UI in transactions for single object retrieval.
X: The annotated CDS view is used to push down the application’s code to SAP HANA DB.
Scope: [VIEW]
ObjectModel. To support the decision on cache strategies for higher layers and to enable client-side statement rout
usageType.da ing using these caches, each CDS view can be assigned to a data class
taClass
(@ObjectModel.usageType.dataClass).
The different data classes correspond with different life time cycles:
TRANSACTIONAL data: The CDS view provides data that is written or changed in high volume trans
actions or in background processing. Examples: Header or items for sales order processing or financial
bookings.
MASTER data is read or changed but not written in high volume transactions or in background proc
essing. This data typically drives the business process decisions when business logic is executed. It is
also displayed to the end user as context information or to enable user decisions when the transac
tions are executed manually. Examples are material data, business partner data, or account data.
ORGANIZATIONAL data describes the organizational structure of a company and its business proc
esses. You can consider it as a special kind of MASTER data. Examples are sales unit, distribution
channel and cost center.
CUSTOMIZING data describes how a concrete business process is executed in a customer system
landscape. This data typically consists of a content that is delivered by SAP and added to by the cus
tomer. Examples are countries, units of measures, and currencies.
META data classes either specify how the system is configured or describes the technical structure of
entities. Typically, this type of data is part of content that is shipped to customers. Examples are DDIC
structures, field controls, and authorization objects.
MIXED data classes should be used if the annotated CDS view contains tables with data that repre
sents multiple data classes.
Scope: [VIEW]
ObjectModel. Defines the DDIC database table name of the active view. This requires
writeActiveP @ObjectModel.transactionalProcessingEnabled: true
ersistence
Scope: [VIEW]
ObjectModel. Defines the DDIC database table name of the draft data. This requires
writeDraftPe @ObjectModel.transactionalProcessingEnabled: true
rsistence
Scope: [VIEW]
ObjectModel. Enables the transactional runtime support. It may only be defined on root view level
writeEnabled - (@ObjectModel.compositionRoot: true).
Deprecated!
Caution
Do not use this annotation an more! It is replaced by
ObjectModel.transactionalProcessingEnabled.
Scope: [VIEW]
BOPF - Depending on the specified persistence information, we can distinguish between the folllowing
scenarios:
a) writeActivePersistence: Active data (defined by that CDS view) is directly modified by the
transactional runtime (without having any kind of draft).
b) writeDraftPersistence: Active data (defined by that CDS view) is only indirectly modified by
a draft.
Examples
Example 1
Sample Code
@ObjectModel.modelCategory: #BUSINESS_OBJECT
@ObjectModel.compositionRoot: true
define view I_SalesOrder
association [0..*] to I_SalesOrderItem as _Item ... {
@ObjectModel.association.type: #TO_COMPOSITION_CHILD
_Item, ...
}
define view I_SalesOrderItem
association [1..1] to I_SalesOrder as _SalesOrder ... {
@ObjectModel.association.type: [#TO_COMPOSITION_ROOT,
#TO_COMPOSITION_PARENT]
_SalesOrder, ...
}
Example 2
Sample Code
Example 3
Sample Code
Example 4
Sample Code
Example 5
This example demonstrates how you can define the transactional behavior
@ObjectModel.compositionRoot: true
@ObjectModel.transactionalProcessingEnabled: true
@ObjectModel.writeDraftPersistence: ‘<DraftDDICTable>’
define view I_MaterialWithDraft ... {
...
}
Capture OData-related aspects to expose data gained from a CDS entity in an OData service.
@Scope:[#VIEW, #TABLE_FUNCTION]
Annotation OData
{
publish : Boolean default true;
};
Usage
Annotation Meaning
Values:
Value Description
false Defines that this CDS entity cannot be exposed for an OData
service
Note
When the CDS entity is activated, the OData service is generated automatically. Before you can open and
use the OData service, it also needs to be activated using transaction /IWFND/MAINT_SERVICE manually.
For further information, see the Related Information below.
Examples
This example demonstrates how you can define the SEPM_I_SalesOrder CDS entity that exposes data to an
OData service.
Here, an OData service is generated for the CDS entity. The data is provided from the database table snwd_so.
Sample Code
@OData.publish:true
define view SEPM_I_SalesOrder as select from snwd_so {
...
}
Related Information
This annotation marks a view as searchable. You define the fuzziness threshold as well as the specifics of term
mappings at element level.
@Scope:[#VIEW, #TABLE_FUNCTION]
Annotation Search
{
searchable : Boolean default true;
};
@Scope:[#ELEMENT]
Annotation Search
{
defaultSearchElement : Boolean default true;
ranking : String(6) enum { HIGH = 'high'; MEDIUM = 'medium'; LOW = 'low'; }
default #MEDIUM;
fuzzinessThreshold : Decimal(3,2);
termMappingDictionary : String(128);
Usage
Annotation Meaning
Search.searchable Defines if a CDS view or entity is generally relevant for search scenarios. This annotation
must be set in case other search-related annotations are being defined for elements of the
respective CDS view or entity. The annotation offers a general switch and a means to quickly
detect whether a view is relevant or not.
Scope: #View
Values:
Value Description
Boolean (true, false) Defines whether a view is relevant for search or not.
Default: true
Search.defaultSearc Specifies that the element is to be considered in a freestyle search (for example a
hElement SELECT…) where no columns are specified.
Usually, such a search must not operate on all elements – for performance reasons, and be
cause not all elements (e.g. internal keys) do qualify for this kind of access.
Scope: #Element
Values:
Value Description
Default: true
Search.ranking Specifies how relevant the values of an element are for ranking, if the freestyle search terms
match the element value.
Scope: #Element
Values:
Value Description
Search.fuzzinessThr Specifies the least level of fuzziness (with regard to some comparison criteria passed at run
eshold time) the element has to have to be considered in a fuzzy search at all.
Note
A fuzzy search enables a certain degree of error tolerance and returns records even if
the search term contains additional or missing characters or other types of spelling er
rors.
Note
To perform a fuzzy search you have to set the search mode to fuzzy in the customiz
ing settings of your ABAP system. Find the customizing node under SAP NetWeaver
If in the customizing a value for Fuzzy Similarity is present, the value of the pa
rameter Search.fuzzinessThreshold will become void.
Scope: #Element
Values:
Value Description
Decimal (3,2) The least level of fuzziness the element has to have to be
considered in a fuzzy search at all, e.g. 0.7.
Search.termMappingD Specifies the table that holds the term mappings (synonyms) to be considered in the con
ictionary text of a search on this view.
Scope: #Element
Evaluation Runtime (Engine): No engine usage right now. Reserved for future usage.
Values:
Value Description
Search.termMappingL Specifies one or multiple list IDs within the term mapping dictionary mentioned before.
istID
The list is implemented as a column of the term mapping table, with the list ID as content of
this column. This concept has the aim to enable overarching term mapping dictionaries
while being able to separate domain-specific content at the same time.
Scope: #Element
Evaluation Runtime (Engine): No engine usage right now. Reserved for future usage.
Values:
Value Description
Array of String(32) Defines one or more columns of the term mapping diction
ary.
Used by the core engines for data processing, analytics, and data consumption
@Scope:[#ELEMENT, #PARAMETER]
Annotation Semantics
{
telephone
{
type : array of String(10) enum { HOME; CELL; WORK; FAX; PREF; TEXT;
VOICE; VIDEO; PAGER; TEXT_PHONE; } default #PREF;
};
eMail
{
type : array of String(10) enum { HOME; WORK; PREF; OTHER; } default #PREF;
address : Boolean default true;
from : Boolean default true;
sender : Boolean default true;
to : Boolean default true;
cc : Boolean default true;
Usage
Semantic annotations are used to inform the client as to which of the elements contain a phone number, a part
of a name or address, or something relating to a calendar event. They must not be bound, for example, to a
dedicated consumption channel. They need to be available for consumption through OData, (S)QL, and so on.
Semantic annotations complement the concept of semantic data types, while semantic data types always
introduce specific behavior in the provider/core infrastructure (through dedicated operations or conversion
functions).
Semantic annotations allow the standardizing of semantics that only have an impact on the consumption side
(such as telephone number, mail address, city, and so on).
Annotation Meaning
Evaluation Runtime (Engine): SADL: Translates CDS annotations into the corresponding OData annotations (Exception:
Semantics.address.number and Semantics.address.streetNoNumber)
Values:
Semantics.address.type[ ] Description
Values:
String(10)
Value Description
Default
Annotations belonging to Semantics.amount contain a monetary amount, and the corresponding currency code is con
tained in the referenced field.
Scope: [ELEMENT]
Values:
Annotations belonging to Semantics.businessDate contain information about changes of database table records.
Evaluation Runtime (Engine): *Business data often carries time validities. When accessing data, one usually intends to get
the most current or a specific state according to a defined date. It is mandatory for the engine to know the semantics in
order to carry out a generic validity evaluation.
Note
Many objects used in the Business Suite store data in a way that requires an algorithm to derive the actual data for a
validity state. The annotation must not be used if a generic evaluation would yield incorrect results.
Values:
Evaluation Runtime (Engine): SADL: Translates CDS annotations into the corresponding OData annotations
Example
1 - 31
Example
1 - 366
Semantics.calendar.halfyear
Example
The string matches the regex
pattern 0[1-9]|1[0-2]
Example
The string matches the regex
pattern [1-4]
Example
The string matches the regex
pattern 0[1-9]|[1-4]
[0-9]|5[2-3]
Example
The string matches the regex
pattern -?([1-9][0-9]
{3,}|0[0-9]{3})
Semantics.calendar.yearHalfyear
Example
The string matches the regex
pattern -?([1-9][0-9]
{3,}|0[0-9]{3})
(0[1-9]|1[0-2])
Example
The string matches the regex
pattern -?([1-9][0-9]
{3,}|0[0-9]{3})[1-4]
Example
The string matches the regex
pattern -?([1-9][0-9]
{3,}|0[0-9]{3})
(0[1-9]|[1-4][0-9]|
5[2-3])
Annotations belonging to Semantics.calendarItem follow the iCalendar standard (RFC5545 ) for representing and ex
changing calendaring and scheduling information such as events, to-dos, journal entries, and free or busy information, in
dependent of any particular calendar service or protocol
Values:
Note
Applications must treat x-
name and iana-token values
they do not recognize the
same way as they would the
PRIVATE value.
Example
LOCATION:Conference Room
- F123\, Bldg. 002
LOCATION;ALTREP="htt
p://xyzcorp.com/
conf-rooms/
f123.vcf":
Conference Room -
F123\, Bldg. 002
Evaluation Runtime (Engine): SADL: Translates CDS annotations into the corresponding OData annotations
Values:
Value Description
This can be either an ISO code or an SAP currency code (data type CUKY).
Scope: [ELEMENT]
Evaluation Runtime (Engine): SADL: Translates CDS annotations into the correspond
ing OData annotations
Note
The attribute address should be used in case a mail address is included – independent from the specialized seman
tics from, sender, to, cc, or bcc.
Evaluation Runtime (Engine): SADL: Translates CDS annotations into the corresponding OData annotations
Semantics.email.type Description
Values: String(10)
Value Description
Annotations belonging to Semantics.fiscal are required for time-based calculations in analytical use cases.
Evaluation Runtime (Engine): Some attributes contain the respective information (as plain integers), and the processor
needs the semantics in order to identify them.
Example
The string matches the regex
pattern [0-9]{3}
Example
The string matches the regex
pattern [1-9][0-9]{3}
Example
The string matches the regex
pattern ([1-9][0-9]{3})([0-9]
{3})
Values:
Semantics.imageUrl
Scope: [ELEMENT, PARAMETER]
Evaluation Runtime (Engine): SADL: Translates CDS annotations into the correspond
ing OData annotations
Evaluation Runtime (Engine): SADL: Translates CDS annotations into the correspond
ing OData annotations
Semantics.languageReference This annotation references a field that identifies languages. You can use this annotation
if you cannot define a language as constant value.
Semantics.mimeType This annotation describes the mime type of a resource (identified by a URL or directly
available as binary content).
This is required when accessing the document content, for example, in a content crawl,
during text analysis, or when opening the document for viewing.
In UIs, documents are usually presented with an icon that symbolizes their mime type.
Evaluation Runtime (Engine): SADL: Translates CDS annotations into the corresponding OData annotations
Values:
Evaluation Runtime (Engine): SADL: Translates CDS annotations into the corresponding OData annotations
Values:
Example
ROLE:Project Leader
Annotations belonging to Semantics.quantity contain a measured quantity, and the corresponding unit of measure is con
tained in the referenced field.
Evaluation Runtime (Engine): SADL: Translates CDS annotations into the corresponding OData annotations
Values:
Annotations belonging to Semantics.systemDate specify the date/time that is recorded by the technical infrastructure/
database.
Note
The sub-annotations have the same semantics as the equally named attributes of the businessDate annotation.
The difference is that values contain the date/time of the creation/change and are recorded by the database.
Values:
Evaluation Runtime (Engine): SADL: Translates CDS annotations into the corresponding OData annotations
Values: String(10)
Value Description
FAX Fax
PAGER Pager
Semantics.text This annotation identifies a human-readable text that is not necessarily language-de
pendent.
Evaluation Runtime (Engine): SADL: Translates CDS annotations into the correspond
ing OData annotations
Semantics.time This annotation is used to indicate a date semantic for the NVARCHAR-based ABAP
type TIMS.
Note
There seems to be currently no internationally recognized standard list for units of
measure available.
Annotations belonging to Semantics.url contain a URL, and its mime type is contained in the referenced second field.
Evaluation Runtime (Engine): SADL: Translates CDS annotations into the corresponding OData annotations
Values:
Annotations belonging to Semantics.user define the ID of the user related to the data record.
The attribute id should be used if the user ID without additional semantics is included. If the dedicated semantics of the
user ID are known, the attributes ceratedBy, lastChangedBy or responsible should be used.
Values:
Example 1
The following CDS view fetches the contact data. Here, the annotations assign to the corresponding fields the
relevant semantic information, such as first name, last name, and so on.
Sample Code
Example 2
The following CDS view fetches sales order items. Here, the annotations assign the units and currencies to the
corresponding fields.
Sample Code
@Semantics.currencyCode
currency_code as CurrencyCode,
@Semantics.amount.currencyCode: 'CurrencyCode'
gross_amount as GrossAmount,
@Semantics.unitOfMeasure
unit_of_measure as UnitOfMeasure,
@Semantics.quantity.unitOfMeasure: 'UnitOfMeasure'
quantity as Quantity,
Example 3
The following CDS view fetches geographic data of cities annotating the corresponding location fields
according to a standardized format:
Sample Code
Example 4
The following CDS view fetches language-dependant data annotating the corresponding language fields and
text fields:
Sample Code
9.1.12 UI Annotations
Represent semantic views on business data through the use of specific patterns that are completely
independent of UI technologies.
@MetadataExtension.usageAllowed : true
{
@Scope:[#ENTITY]
headerInfo
{
@LanguageDependency.maxLength : 40
};
trend : ElementRef;
trendCalculation
{
referenceValue : ElementRef;
isRelativeDifference : Boolean default true;
upDifference : DecimalFloat;
upDifferenceElement : ElementRef;
strongUpDifference : DecimalFloat;
strongUpDifferenceElement : ElementRef;
downDifference : DecimalFloat;
downDifferenceElement : ElementRef;
strongDownDifference : DecimalFloat;
strongDownDifferenceElement : ElementRef;
};
responsible : ElementRef;
responsibleName : String(120);
};
@Scope:[#ELEMENT]
selectionField : array of
{
qualifier : String(120);
position : DecimalFloat;
exclude : Boolean default true;
element : ElementRef;
};
@Scope:[#ELEMENT]
facet : array of
{
qualifier : String(120);
@CompatibilityContract: {
c1: { usageAllowed: false },
c2: { usageAllowed: true,
allowedChanges.annotation: [ #REMOVE ],
allowedChanges.value: [ #NONE ]} }
feature : String(40);
id : String(120);
purpose : String(40) enum
{
STANDARD;
HEADER;
QUICK_VIEW;
QUICK_CREATE;
FILTER;
} default #STANDARD;
parentId : String(120);
position : DecimalFloat;
exclude : Boolean default true;
hidden : Boolean default true;
isPartOfPreview : Boolean default true;
isSummary : Boolean default true;
isMap : Boolean default true;
importance : String(6) enum
{
HIGH;
MEDIUM;
LOW;
};
@LanguageDependency.maxLength : 40
label : String(60);
type : String(40) enum
{
COLLECTION;
ADDRESS_REFERENCE;
BADGE_REFERENCE;
};
@Scope: [#ELEMENT]
valueCriticality: array of
{
qualifier : String(120);
value : String(120);
criticality : Integer enum
{
NEGATIVE;
CRITICAL;
POSITIVE;
};
};
@Scope: [#ELEMENT]
connectedFields : array of
{
qualifier : String(120);
@LanguageDependency.maxLength : 40
groupLabel : String(60);
@LanguageDependency.maxLength : 197
template : String(255);
name : String(120);
exclude : Boolean default true;
hidden : Boolean default true;
importance : String(6) enum { HIGH; MEDIUM; LOW; };
type : String(40) enum
{
AS_ADDRESS;
AS_CHART;
AS_CONNECTED_FIELDS;
AS_CONTACT;
AS_DATAPOINT;
AS_FIELDGROUP;
FOR_ACTION;
FOR_INTENT_BASED_NAVIGATION;
STANDARD;
WITH_INTENT_BASED_NAVIGATION;
WITH_NAVIGATION_PATH;
WITH_URL;
} default #STANDARD;
@LanguageDependency.maxLength : 40
label : String(60);
iconUrl : String(1024);
criticality : ElementRef;
criticalityRepresentation : String(12) enum
{
WITHOUT_ICON;
WITH_ICON;
} default #WITHOUT_ICON;
dataAction : String(120);
requiresContext : Boolean default true;
invocationGrouping : String(12) enum { ISOLATED; CHANGE_SET; } default
#ISOLATED;
semanticObjectAction : String(120);
value : ElementRef;
valueQualifier : String(120);
targetElement : ElementRef;
url : ElementRef;
};
};
UI Annotations
Parent Annotation Annotation Type Value Description
Scope:ENTITY
Evaluation Runtime
(Engine): SADL:
Translates CDS anno
tations into the corre
sponding OData anno
tations
Values:
Note
When users open
a SAP Fiori appli
cation, they can
see an image re
lated to the entity
type to which all
items displayed
on that page be
long to.
● WITH_NAVIGATION
_PATH:Maps to
DataFieldWithNavig
ationPath.
DataFieldWithNavig
ationPath is based
on DataField, and
defines a label-
value pair that re
fers to a property of
the OData service
used. The definition
consists of a link to
navigate to a new
target, based on a
navigation property
provided by the
OData service, or
defined in the anno
tation file.
For more informa
tion, see With Navi
gation Path [page
326].
When you use this
type, you can use
the following ele
ments:
○ label
○ value
When you use this
type, you must use
the following ele
ments:
○ targetElement
● WITH_IN
TENT_BASED_NAV
IGATION;
Default: STANDARD;
Default:
WITHOUT_ICON
● WITH_NAVIGATION
_PATH:Maps to
DataFieldWithNavig
ationPath.
DataFieldWithNavig
ationPath is based
on DataField, and
defines a label-
value pair that re
fers to a property of
the OData service
used. The definition
consists of a link to
navigate to a new
target, based on a
navigation property
provided by the
OData service, or
defined in the anno
tation file.
For more informa
tion, see With Navi
gation Path [page
326].
When you use this
type, you can use
the following ele
ments:
○ label
○ value
When you use this
type, you must use
the following ele
ments:
○ targetElement
● WITH_IN
TENT_BASED_NAV
IGATION;
Default: STANDARD;
Default:
WITHOUT_ICON
● WITH_NAVIGATION
_PATH:Maps to
DataFieldWithNavig
ationPath.
DataFieldWithNavig
ationPath is based
on DataField, and
defines a label-
value pair that re
fers to a property of
the OData service
used. The definition
consists of a link to
navigate to a new
target, based on a
navigation property
provided by the
OData service, or
defined in the anno
tation file.
For more informa
tion, see With Navi
gation Path [page
326].
When you use this
type, you can use
the following ele
ments:
○ label
○ value
When you use this
type, you must use
the following ele
ments:
○ targetElement
● WITH_IN
TENT_BASED_NAV
IGATION;
Default: STANDARD;
WITHOUT_ICON
● WITH_NAVIGATION
_PATH:Maps to
DataFieldWithNavig
ationPath.
DataFieldWithNavig
ationPath is based
on DataField, and
defines a label-
value pair that re
fers to a property of
the OData service
used. The definition
consists of a link to
navigate to a new
target, based on a
navigation property
provided by the
OData service, or
defined in the anno
tation file.
For more informa
tion, see With Navi
gation Path [page
326].
When you use this
type, you can use
the following ele
ments:
○ label
○ value
When you use this
type, you must use
the following ele
ments:
○ targetElement
● WITH_IN
TENT_BASED_NAV
IGATION;
Default: STANDARD;
Default:
WITHOUT_ICON
● WITH_NAVIGATION
_PATH:Maps to
DataFieldWithNavig
ationPath.
DataFieldWithNavig
ationPath is based
on DataField, and
defines a label-
value pair that re
fers to a property of
the OData service
used. The definition
consists of a link to
navigate to a new
target, based on a
navigation property
provided by the
OData service, or
defined in the anno
tation file.
For more informa
tion, see With Navi
gation Path [page
326].
When you use this
type, you can use
the following ele
ments:
○ label
○ value
When you use this
type, you must use
the following ele
ments:
○ targetElement
● WITH_IN
TENT_BASED_NAV
IGATION;
Default: STANDARD;
Default:
WITHOUT_ICON
● WITH_NAVIGATION
_PATH:Maps to
DataFieldWithNavig
ationPath.
DataFieldWithNavig
ationPath is based
on DataField, and
defines a label-
value pair that re
fers to a property of
the OData service
used. The definition
consists of a link to
navigate to a new
target, based on a
navigation property
provided by the
OData service, or
defined in the anno
tation file.
For more informa
tion, see With Navi
gation Path [page
326].
When you use this
type, you can use
the following ele
ments:
○ label
○ value
When you use this
type, you must use
the following ele
ments:
○ targetElement
● WITH_IN
TENT_BASED_NAV
IGATION;
Default: STANDARD;
Default:
WITHOUT_ICON
● BULLET_CHART: A
data point is visual
ized as a bullet
chart.
● DONUT:A data
point is visualized
as a donut chart.
● PROGRESS: A data
point is visualized
as a progress indi
cator.
● RATING: A data
point is visualized
as partly or com
pletely filled sym
bols such as stars
or hearts.
Default:
WITHOUT_ICON
ImprovementDirection =
Target:
● Neutral:
1. Value > Toler
anceRange
LowValue and
Value < Ac
ceptanceRan
geLowValue
2. Value > Ac
ceptanceRan
geHighValue
and Value <
ToleranceRan
geHighValue
● Critical
1. Value > Devia
tionRangeLow
Value and
Value < Toler
anceRange
LowValue
2. Value > Toler
anceRange
HighValue and
Value < Devia
tionRange
HighValue
● Negative: Value <
DeviationRange
LowValue and Value
> DeviationRange
HighValue
ImprovementDirection =
Minimize:
ImprovementDirection =
Maximize:
Sideways: Compare
Value < UpDifference
and CompareValue >
DownDifference
StrongDown: Compare
Value < StrongDownDif
ference
For an overview of
@Semantics annota
tions, see Semantics
Annotations [page
445].
Note
If you use This an
notation, you can
not use element
UI.dataPoint.respo
nsibleName.
UI.datapoint responsibleName String (120) # not compatible with This annotation can be
UI.dataPoint.responsible
used as an alternative
to the responsible ele
Caution
ment. Only the name
If you use this anno of the responsible per
tation, you can't use son can be specified
the annotation here.
UI.dataPoint.respon
sible.
Scope: [ELEMENT]
UI.kpi id String(120)
Scope: [ELEMENT]
Evaluation Runtime
(Engine): SADL: Trans
lates CDS annotations
into the corresponding
OData annotations
Caution
Must not be used
when a structured
element is anno
tated, in this case
the annotated ele
ment is the value.
Scope: [ ENTITY]
Evaluation Runtime
(Engine): SADL: Trans
lates CDS annotations
into the corresponding
OData annotations
Values: array of
COL
UMN_STACKED_DUAL_
100;
BAR;
BAR_STACKED;
BAR_STACKED_100;
BAR_DUAL;
BAR_STACKED_DUAL;
BAR_STACKED_DUAL_1
00;
AREA;
AREA_STACKED;
AREA_STACKED_100;
HORIZONTAL_AREA;
HORIZON
TAL_AREA_STACKED;
HORIZON
TAL_AREA_STACKED_1
00;
LINE;
LINE_DUAL;
COMBINATION;
COMBINA
TION_STACKED;
COMBINA
TION_STACKED_DUAL;
HORIZONTAL_COMBI
NATION_STACKED;
HORIZONTAL_COMBI
NA
TION_STACKED_DUAL;
PIE;
DONUT;
SCATTER;
BUBBLE;
RADAR;
HEAT_MAP;
TREE_MAP;
WATERFALL;
BULLET;
VERTICAL_BULLET;
HORIZONTAL_WATER
FALL;
HORIZONTAL_COMBI
NATION_DUAL;
DONUT_100;
UI.chart dimensionAttributes.ro String(10) enum These annotatoions de This annotation de
le termine the visualization
fines the manner in
of a chart.
which a dimension is
● CATEGORY: For ex used within a
ample: Line chart: chart.This is config-
Dimensions for ured differently for
which the role is set each chart type.
to CATEGORY,
make up the X-axis
(category axis). If
no dimension is
specified with this
role, the first di
mension is used as
the X-axis.
● SERIES: For exam
ple:
Line chart: Dimen
sions for which the
role is set to SER
IES make up the
line segments of
the chart, with dif
ferent colors as
signed to each di
mension value. If
multiple dimen
sions are assigned
to this role, the val
ues of all such di
mensions together
are considered as
one dimension and
a color is assigned.
● CATEGORY2
UI.chart measureAttributes.role String(10) enum This annotation deter This annotation de
mines the visualization
fines the manner in
of a chart.
which a measure is
● AXIS_1:
used within a chart.
Example
This is configured dif
Bubble chart: The
ferently for each chart
first measure for
type.
which the role is set
to AXIS_1, or if
none exists, the
first measure for
which the role is set
to AXIS_2, or if
none exists, the
first measure for
which the role is set
to AXIS_3, is as
signed to the feed
UID valueAxis. This
makes up the X-
axis.
● AXIS_2:
For an example, see
the description of
AXIS_1.
● AXIS_3:
For an example, see
the description of
AXIS_1.
Scope: [ENTITY]
Evaluation Runtime
(Engine): SADL: Trans
lates CDS annotations
into the corresponding
OData annotations
Values: array of
Scope: [ ENTITY]
Evaluation Runtime
(Engine): SADL: Trans
lates CDS annotations
into the corresponding
OData annotations
Values: array of
UI.presentationVariant sortOrder.direction String(4) enum ● ASC: Sort in as This annotation de
cending order. fines the sorting direc
● DESC: Sort in de tion of queried collec
scending order.
tions.
UI.lineItem
UI.chart
UI.dataPoint
Evaluation Runtime
(Engine): SADL: Trans
lates CDS annotations
into the corresponding
OData annotations
Scope: [ELEMENT]
Evaluation Runtime
(Engine): SADL: Trans
lates CDS annotations
into the corresponding
OData annotations
Scope: [ELEMENT]
Evaluation Runtime
(Engine): SADL: Trans
lates CDS annotations
into the corresponding
OData annotations
String
UI.facet purpose String(40) enum #not compatible with This annotation speci
UI.facet.parentID
fies the purpose of a
facet; only allowed if
Caution
parentId is not speci
You can only use fied
this annotation, if
parentId is not
specified.
STANDARD;
HEADER;
QUICK_VIEW;
QUICK_CREATE;
FILTER;
default: STANDARD;
- targetElement ele
ment is available
- targetQualifier ele
ment is available
● STATUSINFO_REFE
RENCE
- targetElement ele
ment is available
- targetQualifier ele
ment is available
● URL_REFERENCE
- url element is
available
Evaluation Runtime
(Engine): SADL: Trans
lates CDS annotations
into the corresponding
OData annotations
FOR_ACTION;
FOR_IN
TENT_BASED_NAVIGA
TION;
STANDARD;
WITH_IN
TENT_BASED_NAVIGA
TION;
WITH_NAVIGA
TION_PATH;
WITH_URL;
} default #STANDARD;
label
WITHOUT_ICON
Default: ISOLATED
Example
Scope: [ELEMENT]
Evaluation Runtime
(Engine): SADL: Trans
lates CDS annotations
into the corresponding
OData annotations
Values: array of
FOR_ACTION;
FOR_IN
TENT_BASED_NAVIGA
TION;
STANDARD;
WITH_IN
TENT_BASED_NAVIGA
TION;
WITH_NAVIGA
TION_PATH;
WITH_URL;
} default #STANDARD;
label
WITHOUT_ICON
Default: ISOLATED
Scope: [ELEMENT]
Evaluation Runtime
(Engine): SADL: Trans
lates CDS annotations
into the corresponding
OData annotations
Values: array of
FOR_ACTION;
FOR_IN
TENT_BASED_NAVIGA
TION;
STANDARD;
WITH_IN
TENT_BASED_NAVIGA
TION;
WITH_NAVIGA
TION_PATH;
WITH_URL;
} default #STANDARD;
label
WITHOUT_ICON
Default: ISOLATED
Scope: [ELEMENT]
Evaluation Runtime
(Engine): SADL: Trans
lates CDS annotations
into the corresponding
OData annotations
Values: array of
FOR_ACTION;
FOR_IN
TENT_BASED_NAVIGA
TION;
STANDARD;
WITH_IN
TENT_BASED_NAVIGA
TION;
WITH_NAVIGA
TION_PATH;
WITH_URL;
} default #STANDARD;
label
WITHOUT_ICON
Default: ISOLATED
Its language-depend
ent template specifies
how to render the con
nected fields. The
template consists of
placeholders for val
ues (must be valid
OData simple identifi-
ers - think: variable
names) enclosed in
curly braces, plus
printable characters
and white-space out
side of the curly bra
ces. The example tem
plate {rate}%
({amount}) consists of
two placeholders rate
and amount. The value
to be inserted for rate
will be followed by a
percent sign, the value
to be inserted for
amount will be en
closed in parentheses.
Note that the ""val
ues"" to be inserted
are themselves data
fields and thus can
he first occurrence of
groupLabel for a given
qualifier wins, same
for template. Other oc
currences for the
same qualifier are re
dundant and should
be avoided.
FOR_ACTION;
FOR_IN
TENT_BASED_NAVIGA
TION;
STANDARD;
WITH_IN
TENT_BASED_NAVIGA
TION;
WITH_NAVIGA
TION_PATH;
WITH_URL;
} default #STANDARD;
label
WITHOUT_ICON
Default: ISOLATED
Allow classifying views of the virtual data model in terms of their admissible reuse options and provisioned
content
TRANSACTIONAL_PROCESSING_SERVICE;};
};
};
Usage
VDM is intended to be interpreted by view browsers and other functionality which is based on the virtual data
model.
This classification is used only for SAP internal structuring and interpretation of the CDS entities. Releasing
CDS entities for customers and partners is controlled by additional internal classification of the entities.
Annotation Meaning
VDM.auxiliaryEntity Establishes a connection between an auxiliary entity and its supported entity.
.for.entity
Scope: #VIEW
Evaluation Runtime (Engine): None - Used for SAP internal structuring and interpretation
of the CDS entities
Evaluation Runtime (Engine): None - Used for SAP internal structuring and interpretation
of the CDS entities
Both, the usage type and origin entity have to be defined in parallel.
Scope: #ENTITY
Evaluation Runtime (Engine): None - Used for SAP internal structuring and interpretation
of the CDS views
Values:
Value Description
BASIC Views that form the core data basis without data redundan
cies.
COMPOSITE Views that provide data derived and/or composed from the
BASIC views.
CONSUMPTION Views that serve for specific application purposes and are
defined based upon BASIC or COMPOSITE or
TRANSACTIONAL views.
EXTENSION Technical carrier views for key user driven field extensibility.
DERIVATION_FUNCTION Views that can be used to define derivations (via the annota
tion @Consumption.derivation) for parameter values
and for filter values (via the annotation
@Consumption.filter).
VDM.private Private views represent technical helper views which may only be used by their defining re
sponsibles.
Evaluation Runtime (Engine): None - Used for SAP internal structuring and interpretation
of the CDS entities
Scope: #EXTEND_VIEW
Evaluation Runtime (Engine): None - Used for SAP internal structuring and interpretation
of the CDS entities
Evaluation Runtime (Engine): None - Used for SAP internal structuring and interpretation
of the CDS entities
Values:
Value Description
NONE Not subject to any contract. Default for private and con
sumption VDM views.
PUBLIC_LOCAL_API System local API contract. Default for VDM Basic and Com
posite Views.
Evaluation Runtime (Engine): None - Used for SAP internal structuring and interpretation
of the CDS entities
Values:
Value Description
Evaluation Runtime (Engine): None - Used for SAP internal structuring and interpretation
of the CDS entities
VDM.usage.type Defines the usage scenario, which the VDM CDS entity shall support.
Scope: #ENTITY
Evaluation Runtime (Engine): None - Used for SAP internal structuring and interpretation
of the CDS entities
Values:
Value Description
TRANSACTIONAL_PROCE Used for CDS models which are exposed in services support
SSING_SERVICE ing the transactional processing.
Example 1
Sample Code
@VDM.viewType: #BASIC
define view I_MyBasicView ...
Example 2
Sample Code
@VDM.private: true
@VDM.viewType: #COMPOSITE
define view P_MyPrivateCompositeView ...
Example 3
Sample Code
@VDM.viewExtension: true
extend view I_MyExtendedView with X_IN_I_MyExtendedView ...
Example 4
Lifecycle annotations:
Sample Code
@VDM.lifecycle.contract.type:#PUBLIC_LOCAL_API
define view I_MyPublicLocalAPIView ...
@VDM.lifecycle.contract.type:#PUBLIC_REMOTE_API
define view A_MyPublicRemoteAPIView ...
@VDM.lifecycle.status: #DEPRECATED
@VDM.lifecycle.successor: 'I_MySuccessorView'
define view I_MyDeprecatedView ...
Example 5
Sample Code
Example 6
Sample Code
@VDM.usage.type:[#ACTION_PARAMETER_STRUCTURE]
define abstract entity D_SampleEntityActionParameter ...
@VDM.usage.type: [#EVENT_SIGNATURE]
@VDM.usage.type:[#TRANSACTIONAL_PROCESSING_SERVICE]
@VDM.viewType:#CONSUMPTION
@ObjectModel.transactionalProcessingDelegated:true
define view C_SampleTransactionalProcessingDelegatingView ...
@Event: {sapObjectType: 'SAPObject',...}
define abstract entity MyEventSignature ...
The generic authorization concept is based on the abstract authorization check superclass /BOBF/
CL_FRW_AUTHORITY_CHECK.
/BOBF/CL_FRW_AUTHORITY_CHECK
This abstract class is the superclass of the authorization check classes and acts as an interface definition.
/BOBF/CL_LIB_AUTH_DRAFT_ACTIVE
Authorization class for active or draft version of BO instances - for BOs that have been generated based on the
CDS data model definition
When implementing application-specific authorization classes, you must inherit from this class and implement
the abstract methods of interface /BOBF/IF_LIB_AUTH_DRAFT_ACTIVE.
/BOBF/IF_LIB_AUTH_DRAFT_ACTIVE
Interface used to check the authorizations for active and draft version of BO instances
This interface defines the following methods for implementing authorization checks.
Method Summary
Method Description
Note
Remember
Static authorization checks do not depend on BO instance data such as node attributes.
This method is usually called before the execution of a BOPF core service to check whether the user has
authorization to execute a specific task, such as modifying data or performing an action (regardless of a
specific instance that might be performed for). The context parameter IS_CTX provides information about the
situation in which the authorization check will be executed.
Signature
Parameters
Parameter Description
IS_CTX Provides context information for the authorization check (authorization context)
EO_MESSAGE Message object used for returning information, warning, or error messages related to the
execution of the authorization check
RV_FAILED The value (true/false) indicates whether the authorization check failed
The source code listing below provides you with an example for implementing static checks based on the sales
order application scenario. You can use this source code as a template for your own implementations.
method /BOBF/IF_LIB_AUTH_DRAFT_ACTIVE~CHECK_STATIC_AUTHORITY.
case is_ctx-activity.
when /BOBF/CL_FRW_AUTHORITY_CHECK=>SC_ACTIVITY-create.
" Check the creation of new (draft) instance here
" This check is executed before a new (draft) instance data is
created
when /BOBF/CL_FRW_AUTHORITY_CHECK=>SC_ACTIVITY-display.
" Note that DISPLAY authorization mostly depends on the DCL of the BO
CDS view.
" For DISPLAY authorization checks, this method is only executed in rare
use cases.
when /BOBF/CL_FRW_AUTHORITY_CHECK=>SC_ACTIVITY-delete.
" Check the DELETE authorization here...
if sy-subrc = 0.
rv_failed = abap_false. " Grant deletion
else. " Deny deletion
ls_message_textid = /bobf/cm_lib=>no_auth_delete.
endif.
when /BOBF/CL_FRW_AUTHORITY_CHECK=>SC_ACTIVITY-change.
" Check the static UPDATE authorization here...
if sy-subrc = 0.
rv_failed = abap_false. " Grant update
else. " Deny update
ls_message_textid = /bobf/cm_lib=>no_auth_update.
endif.
when /BOBF/CL_FRW_AUTHORITY_CHECK=>SC_ACTIVITY-execute.
case is_ctx-action_name.
when 'SET_TO_DELIVERED'.
" Check static authorization for changing status of sales orders
here...
if sy-subrc = 0.
rv_failed = abap_false. " Grant creation
else. " Deny creation
ls_message_textid = /bobf/cm_lib=>no_auth_execute_action. "
Generic message
endcase.
endif.
endmethod.
Related Information
An instance-based authorization check depends on a BO instance data such as node attributes. Applications
must implement this method to check whether the current user has the authorization required to perform a
specific task for the given BO instance.
The context parameter IS_CTX is used as an input parameter in the method call. It provides information about
the situation in which the authorization check is invoked (when performing a certain action for example).
Signature
Parameters
Parameter Description
IS_CTX Provides context information for the authorization check (authorization context)
IT_KEY Set of BOPF keys for BO instances for which the authorization check is to be executed
IO_READ Reference that provides read access to the data of the business object instances
More :
EO_MESSAGE Message object used for returning information, warning, or error messages related to the
execution of the authorization check
ET_FAILED _KEY Set of keys for node instances (subset of IT_KEY) that do not match the criteria for authori
zation checks (keys with failed authority check)
Example
The following source code (listing below) provides you with an example (or rather a template) for implementing
an instance-specific check based on the sales order application scenario.
method /bobf/if_lib_auth_draft_active~check_instance_authority.
data:
lv_denied type abap_bool, " Specifies whether the
user access is granted or denied
lt_sales_order type ztdemo_i_salesorder_wd, " Instance data typed with
node's combined table type
ls_message_textid type scx_t100key, " T100 key with parameters
lt_attributes type /bobf/t_frw_name. " BO attribute names
" Retrieve the data of the requested node instance
io_read->retrieve(
exporting
iv_node = is_ctx-node_key
it_key = it_key
importing
et_data = lt_sales_order
et_failed_key = et_failed_key
).
Related Information
The context information is provided with parameter IS_CTX that provides further information about the
situation in which the authorization check will be executed. This allows applications to closely control the
behavior depending on the situation. It is used as an input parameter for all methods of the authorization check
class.
BO_KEY Key of the business object that the authorization will be executed for
NODE_KEY Node ID of the BO that the authorization check will be executed for
ACTIVITY Activity type (create, change, delete and so on) that the authorization check will be exe
cuted for
ACTION_NAME Name of the business object’s action that the authorization check will be executed for
Here are descriptions of some of the changes of interest to developers made to ABAP Programming Model for
SAP Fiori.
Remember
This documentation is integral part of the client installation of ABAP Development Tools (ADT).
Apart from deriving values for parameters, you can now derive filters from foreign entities. The frameworks
allows you to implement single-value filters or filter ranges that are derived from foreign entities. The filter
value is set automatically in CDS if it is annotates with the relevant annotations that provide the navigation
information to the single value or the filter range. You have the option to determine the value(s) for the filter by
using a parameter or an element binding.
For further information, look at Deriving Values from Foreign Entities [page 247].
A draft-enabled association retrieves active data, if you follow the association from the active source instance,
and draft data, if you follow it from the draft source instance. An association that is not draft-enabled always
retrieves active data even if the source entity is a draft instance. There are associations that are draft-enabled
by default and associations for which draft-enablement needs to be implemented. This implementation is done
by annotations on the association in the CDS view. It is now possible to draft-enable associations with
cardinality to-many
For further information, refer to Draft-Enabling for Reverse Associations [page 294].
Aggregate Data is used to combine numerical values to form a single value of signifying meaning. Aggregate
functions, such as sum, maximum, minimum and average, as well as counting options are now available to be
implemented in CDS and displayed in your SAP Fiori App. Annotations are used to mark the elements as
measures whose values can be aggregated. The other elements are interpreted as dimensions or attributes of
dimensions. The data records can be grouped by the dimensions whereby the measure values are aggregated
with regard to the group.
For further information, see Using Aggregate Data in SAP Fiori Apps [page 263].
A draft-enabled association retrieves active data, if you follow the association from the active source instance,
and draft data, if you follow it from the draft source instance. An association that is not draft-enabled always
retrieves active data even if the source entity is a draft instance. There are associations that are draft-enabled
by default and associations for which draft-enablement needs to be implemented. This implementation is done
by annotations on the association in the CDS view.
Temporal data is data that is time-dependent. The data properties are only valid during a specific validity
period. If temporal data is stored in the database with table fields that define the beginning and the end of the
valid time frame, you can model temporal data in CDS entities with the help of annotations that specify the
relevant elements for the temporal data. This gives you the opportunity to retrieve temporal data by using a
query option in OData requests.
It is now possible to derive a value for a parameter of one CDS entity from a different one. This helps you to
create dependencies between two different entities. The parameter is filled automatically in CDS if it is
annotated with the relevant annotations that provide the navigation information to the value in the foreign
entity. You have the option to determine the value of the foreign entity by using a parameter or an element
binding.
For further information, look at Deriving Values from Foreign Entities [page 247].
Filtering on virtual elements requires the substitution of the filter condition with a condition that takes only
persistent elements into account. A new ABAP API provides a simple condition factory that uses methods for
relational and logical operators. This makes it easy to concatenate several logical expressions.
For further information, look at Creating Conditions with the Simple Condition Factory [page 218].
Business applications that follow a stateless programming paradigm are based on a RESTful protocol for
communication. In various concept topics, we explain how the ABAP application infrastructure is used in
transactional applications to ensure the data consistency for draft and active instances of business objects in
the context of stateless programming.
Business applications require an authorization concept for their data and for the operations on their data.
Authorizations for CRUD operations and specific business-related activities are based on specific authorization
exists that are implemented using a coreesponding BOPF API. Applications using business objects that have
been generated based on the CDS data model definition, use a new BOPF API to implement their application-
specific authorization checks. This API allows you to implement the authorization checks for active or draft
version of BO instances.
For further information, look at: Implementing Authorizations for Generated Business Objects [page 160]
Note
This authorization API has already been released with SAP NetWeaver AS for ABAP 7.51 innovation
package, SP02.
Virtual elements represent transient fields in business applications. They come into play if these fields are not
provided as part of the original persistence data model or cannot be easily integrated in CDS so that their
values can be calculated directly on SAP HANA.
For further information, look at: Using Virtual Elements in CDS [page 206]
As the application developer, you have now the option to develop a completely new transactional apps for SAP
Fiori UI that also provide the draft data support. This can be important for you, if you have to provide the end
user with capabilities to store changed data at any time in the backend and proceed at a later point in time or to
recover such data, even if the application client has crashed.
For further information, look at: Developing New Transactional Apps with Draft Capabilities [page 105]
With dynamic fields and entities, you can control the visibility and changeability of fields or the entire business
object nodes depending on the value selected from another field. In the context of the ABAP programming
model for SAP Fiori, the field and entity control is a means in a transactional scenario that you can provide as
information to the OData service on how data has to be displayed for consumption on the SAP Fiori UI.
For further information, look at: Dynamic Field and Entity Control [page 194]
In addition to the field and entity control, you can also implement the visibility and changeability of actions. To
provide the dynamic action control, the BOPF property determinations are used.
For further information, look at: Dynamic Action Control [page 201]
A combination of various technologies such as CDS (Core Data Services), BOPF (Business Object Processing
Framework), SADL (Service Adaption Description Language) and SAP Gateway.
It is introduced with SAP NetWeaver AS ABAP 7.5 to support the development of all types of SAP Fiori
applications like transactional, search, analytics and planning apps.
ABAP CDS entities (also referred as CDS entities) are data models based on the DDL (Data Definition
Language) specification and are managed by the ABAP Dictionary.
An ABAP CDS view (also referred as CDS view) is defined for existing database tables, database views, or for
other CDS views by using the ABAP CDS statement DEFINE VIEW within a DDL source.
A CDS view serves to define the structure of an SQL view and represents a projection onto one or several ABAP
Dictionary tables or ABAP Dictionary views.
For each CDS view, two objects are created in the ABAP Dictionary:
● An SQL view
● The actual CDS entity.
Active Data
Active data represents the state of a business entity (a business object, nodes of a business object) which is
stored in the existing persistence (or original persistence).
BOPF
The Business Object Processing Framework (in short: BOPF) is an ABAP OO-based framework that provides a
set of generic services and functionalities to speed up, standardize, and modularize development of business
applications.
It manages the entire life cycle of business objects and covers all aspects of business application development.
Furthermore, BOPF is a fundamental technology of the ABAP Application Framework.
In BOPF, a business object is represented as a hierarchical tree of nodes. A single node includes a set of
semantically related attributes and the corresponding business logic. For each node, several types of entities
can be defined to describe the specific business logic part of the business object.
CDS provides an infrastructure for defining and consuming semantically rich data models in SAP HANA.
In particular, ABAP CDS provides a framework for defining and consuming semantic data models on the central
database of the application server AS ABAP. The specified data models are based on the data definition
language (DDL) and the data control language (DCL).
CDS Annotations
An annotation enriches a definition of a model element in the CDS with metadata. It can be specified for
specific scopes of a CDS objects, namely specific places in a piece of CDS source code.
Consumption Model
Data model that represents an OData service by bundling a set of SAP Gateway service artifacts for a specific
use-case (consumption).
ABAP development object used to define an ABAP CDS entity (for example, a CDS view).
After creation of a Data Definition, the developer is able to use the standard functions of the ABAP Workbench -
such as syntax check, activation, or connecting to the Transport Organizer. The developer creates a Data
Definition with the help of a wizard in ABAP Development Tools.
Data Model
Root entity that represents a certain self-contained business object and is used to define a people-centric view
on respective business information.
Draft Data
A draft instance represents the transient state of a business entity (a business object, nodes of a business
object) until it is permanently stored in the original persistency as an active instance. A draft instance is used to
store inactive data in the draft persistency until its transition to the active data.
Element List
An element list in a CDS view contains all parameters and their aliases that are used by CDS annotations.
Example
If you need to use the parameter p_StartDate, you add it to the element list of the corresponding CDS
view by following declaration:
$parameters.p_StartDate as StartDate
EPM
Enterprise Procurement Model (in short: EPM) is a demo application that integrates many SAP NetWeaver
technologies used by SAP Business Suite applications.
It is intended to be used for demonstration and testing purposes in the SAP NetWeaver technology stack. This
demo application is based on real-world business logic and scenarios that can be used for various testing
approaches and also provides you with utilities to generate meaningful test data.
The ETag check is used to determine whether two representations of a business entity, such as an active
instance and the corresponding draft BO instance, are the same (draft scenario). If the representation of the
entity ever changes, a new and different ETag value is assigned.
Usually, fields like last changed timestamp, hash values, or version counters are used as ETags.
Exposure
The CDS data model (CDS views), along with the CDS annotations fully specify the resulting OData model and
the runtime behavior - without any additional metadata or OData-specific implementation.
Exposure means that the related CDS views, including all extensions and all applicable annotations, are
mapped to a corresponding OData service.
Full text searching (or just text search) provides the capability to identify natural-language terms that satisfy a
query and, optionally, to sort them by relevance (ranking) to the query.
Fuzzy Search
Fuzzy search is a fast and fault-tolerant search feature of SAP HANA. The concept behind the fault-tolerant
search means that a database query returns records even if the search term (user input) contains additional or
missing characters, or other types of spelling errors.
Hub System
When data in database tables is modified by application programs, it must be ensured that the data is
consistent after the changes have been made. This is particularly important when data is edited in the
database. The time span in which a consistent data state is transferred to another consistent state is known as
an LUW (Logical Unit of Work).
The Open Data (in short: OData) protocol is a Web protocol for querying and updating data. It applies several
Web technologies such as HTTP, Atom Publishing Protocol, and JSON to provide access to information from a
variety of applications.
OData is based on industry standards and offers database-like access to business data using REST-based
(Representational State Transfer) architecture.
SADL
Service Adaptation Description Language (in short: SADL) is an ABAP technology that enables the
consumption of entity relationship-like data models in ABAP based on a model-driven approach.
In context of SAP HANA, SADL enables fast read access to database data for scenarios on mobile and desktop
applications using query push-down.
SAP Fiori UX
SAP Fiori is the new user experience (UX) for SAP software that applies modern design principles. SAP
solutions, such as the SAP Business Suite powered by SAP HANA, are using the SAP Fiori UX to provide a
personalized, responsive, and simple user experience.
SAP Gateway
Interface for communication between SAP backend system and external applications using the CPI-C protocol
SAP Gateway handles the communication between a client and the SAP Business Suite backend and is
available as an SAP NetWeaver Application Server ABAP (AS ABAP) add-on, which you can be installed on top
of SAP Business Suite application platform. SAP Gateway uses OData services to provide backend data and
functions, and processes HTTPS requests for OData services.
Hyperlinks
Some links are classified by an icon and/or a mouseover text. These links provide additional information.
About the icons:
● Links with the icon : You are entering a Web site that is not hosted by SAP. By using such links, you agree (unless expressly stated otherwise in your
agreements with SAP) to this:
● The content of the linked-to site is not SAP documentation. You may not infer any product claims against SAP based on this information.
● SAP does not agree or disagree with the content on the linked-to site, nor does SAP warrant the availability and correctness. SAP shall not be liable for any
damages caused by the use of such content unless damages have been caused by SAP's gross negligence or willful misconduct.
● Links with the icon : You are leaving the documentation for that particular SAP product or service and are entering a SAP-hosted Web site. By using such
links, you agree that (unless expressly stated otherwise in your agreements with SAP) you may not infer any product claims against SAP based on this
information.
Example Code
Any software coding and/or code snippets are examples. They are not for productive use. The example code is only intended to better explain and visualize the syntax
and phrasing rules. SAP does not warrant the correctness and completeness of the example code. SAP shall not be liable for errors or damages caused by the use of
example code unless damages have been caused by SAP's gross negligence or willful misconduct.
Gender-Related Language
We try not to use gender-specific word forms and formulations. As appropriate for context and readability, SAP may use masculine word forms to refer to all genders.
SAP and other SAP products and services mentioned herein as well as
their respective logos are trademarks or registered trademarks of SAP
SE (or an SAP affiliate company) in Germany and other countries. All
other product and service names mentioned are the trademarks of their
respective companies.