- Developers
- Tutorials
- Enhance an ABAP Core Data Services (CDS) View in SAP Cloud Platform, ABAP Environment
Enhance an ABAP Core Data Services (CDS) View in SAP Cloud Platform, ABAP Environment
-
Join the conversation on Facebook
-
Join the conversation on Twitter
-
Subscribe to the YouTube Channel
-
Join the conversation on LinkedIn
-
View our projects on GitHub
-
Share via email
Enhance an ABAP Core Data Services (CDS) View in SAP Cloud Platform, ABAP Environment
You will learn
- How to add value help using a filter
- How to add textual information using associations
- How to concatenate two elements, using a built-in function for CDS
- How to convert currencies using a built-in function for CDS
- How to create an object page
- How to add a CASE statement
Prerequisites
You can then use some of these features in productive development to make your applications more powerful and more user-friendly. By the end of this tutorial, your application should include a list page and an object page, which should look like this:


Throughout this tutorial, objects name include a suffix, such as XXX
. Always replace this with your group number or initials.
To make the input fields more useful, you will now add input value help to the field AgencyID
.
-
Specify the source of the value help. This works a bit like a join: You need to point to an entity, and field common to both the entity and your CDS view. In this case, you will point to
AgencyID
in the CDS entity/DMO/I_Agency
. Add the following annotation to your fieldAgencyID
.@Consumption.valueHelpDefinition: [{ entity: {name: '/DMO/I_Agency', element: 'AgencyID'} }]
-
You also need to expose this second entity in the OData service. To do this, add the entity
/DMO/I_Agency
to your service definition, so the complete definition looks like this:@EndUserText.label: 'Service exposes Travel Data XXX' define service Z_EXPOSE_TRAVEL_XXX { expose Z_C_TRAVEL_DATA_XXX as Travel; expose /DMO/I_Agency as Agency; }
-
Format, save, and activate both CDS view and service definition (
Shift+F1, Ctrl+S, Ctrl+3
). -
Refresh your Fiori Elements preview and choose value help for the input field
AgencyID
. -
Now the value help appears. Enter the country key DE and choose Go. Only German agencies appear on the list.
-
Repeat this step for
CustomerID
:@Consumption.valueHelpDefinition: [{entity: {name: '/DMO/I_Customer', element: 'CustomerID' }}]
-
Also, expose this entity in the service definition:
expose /DMO/I_Customer as Customer;
Next, you will make the Agency field more readable by adding the agency name to the ID, using a text association.
CDS associations are simply specifications of joins, always in the same place in the syntax. The main advantage of an association is reuse: Once you have specified an association once, you can conveniently string several associations together in a path. In this case, however, you will use a simple association.
For more information, see:
- ABAP Keyword Documentation: CDS - Associations
-
Add the following 2 statements to your CDS view,
Z_C_TRAVEL_DATA_XXX
, just before the list of fields. The first statement creates an association from the source CDS entityZ_C_TRAVEL_DATA_XXX
to the target CDS entity/DMO/I_Agency
, joined on the fieldAgencyID
. The source entity is represented by the alias$projection
, because you cannot use the original name in a path statement. The target entity is represented by its alias name_Agency
.association [1..1] to /DMO/I_Agency as _Agency on $projection.AgencyID = _Agency.AgencyID
-
Now add the following annotation to the field
AgencyID
:@ObjectModel.text.association: '_Agency'
-
Check that the association has been added to the field list. (This should have been done automatically when you inserted the signature of
/DMO/I_TRAVEL_U
.) -
Format, save, and activate (
Shift+F1, Ctrl+S, Ctrl+F3
). -
Make sure that the entity
/DMO/I_Agency
has been added to your service definition. (You should have done this in step 1.) -
Refresh your Fiori Elements preview. The agency name should now be shown, with the ID number in parentheses.
-
Repeat for the fields
CustomerID
andCurrency_Code
:association [1..1] to /DMO/I_Customer as _Customer on $projection.CustomerID = _Customer.CustomerID association [0..*] to I_CurrencyText as _CurrencyText on $projection.CurrencyCode = _CurrencyText.Currency
@ObjectModel.text.association: '_Customer' @ObjectModel.text.association: '_CurrencyText'
-
Also make sure these associations are added to the list of fields:
//Associations _Customer _CurrencyText
ABAP has many built-in SQL functions for both numeric and string fields.
For more information on these functions, see : ABAP Keyword Documentation: SQL Functions.
You will use a simple one to easily merge two fields. The two fields are provided by the association _Customer
.
-
Add an association.
association [1..1] to /DMO/I_Customer as _Customer on $projection.CustomerID = _Customer.CustomerID
-
After
CustomerID
, add a comma, then add the functionconcat_with_space
using auto-complete (Ctrl+Space
); then add the aliasas Addressee
.concat_with_space(_Customer.Title, _Customer.LastName, 1) as Addressee,
-
Also make sure this association is added to the list of fields:
CDS //Associations _Customer
- Format, save, and activate these objects using
Shift+F1, Ctrl+S, Ctrl+F3
. -
Check the result in the data preview, by clicking in the editor and choosing Open With > Data Preview from the context menu. The result should look like this.
-
Now you have the addressee, you may want to comment out the text association for
CustomerID
.
It would be nice to find out how much money each Agency has received in total. To do this, you first need to convert all the sums paid to one currency. To do this, you will again use a built-in function. For more information, see the ABAP Keyword Documentation: ABAP CDS - Conversion Functions for Units and Currencies
- Convert the price (**
TotalPrice
**) of each line item to US Dollars. Again, you do this using a built-in conversion function. You simply have to define the variables you are using for amount, source currency, etc, and the built-in function does the rest.You need to cast the character value
'USD'
to the correct type and length,abap.cuky( 5 )
.You may get a warning: “Reference information missing…”. Ignore this for now.
currency_conversion( amount => TotalPrice, source_currency => CurrencyCode, round => 'X', target_currency => cast('USD' as abap.cuky( 5 )), exchange_rate_date => cast('20200429' as abap.dats), error_handling => 'SET_TO_NULL' ) as PriceInUSD,
- Format, save, and activate (
Shift+F1, Ctrl+S, Ctrl+3
) -
If you check the result in the data preview, it should look like this.
-
Now you will remove the warning. If you select the warning, then choose Problem Description from the context menu, you will see that you need to add an annotation,
•Semantics.amount.currencyCode
. However, this will simply add the original currency code (e.g.NOK
) to thePriceInUSD
column. Also, you can only add an element name to the annotation, not a literal such as'NOK'
. So you need to:- Create a column,
TargetCurrency
- Give it the value of the literal
- Cast the string literal to a currency type,
abap.cuky
- Add the semantic annotation to
PriceInUSD
Your code should now look like this:
//Conversion to USD @Semantics.currencyCode: true cast( 'USD' as abap.cuky ) as TargetCurrency,
- Create a column,
The code for your CDS entity should look like this:
@AbapCatalog.sqlViewName: 'ZCTRAVEL_xxx'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Consumption view for travel XXX'
@Metadata.allowExtensions: true
@Search.searchable: true
define view Z_C_travel_xxx
as select from /DMO/I_Travel_U
association [1..1] to /DMO/I_Agency as _Agency on $projection.AgencyID = _Agency.AgencyID
association [1..1] to /DMO/I_Customer as _Customer on $projection.CustomerID = _Customer.CustomerID
association [0..*] to I_CurrencyText as _CurrencyText on $projection.CurrencyCode = _CurrencyText.Currency
{
///DMO/I_Travel_U
key TravelID,
@Consumption.valueHelpDefinition: [{entity: {name: '/DMO/I_Agency', element: 'AgencyID'}}]
@ObjectModel.text.association: '_Agency'
AgencyID,
@Consumption.valueHelpDefinition: [{entity: {name: '/DMO/I_Customer', element: 'CustomerID' }}]
@ObjectModel.text.association: '_Customer'
CustomerID,
concat_with_space(_Customer.Title, _Customer.LastName, 1) as Addressee,
BeginDate,
EndDate,
BookingFee,
@Semantics.amount.currencyCode: 'CurrencyCode'
TotalPrice,
//Currency Conversion
currency_conversion(
amount => TotalPrice,
source_currency => CurrencyCode,
round => 'X',
target_currency => cast('USD' as abap.cuky( 5 )),
exchange_rate_date => cast('20200429' as abap.dats),
error_handling => 'SET_TO_NULL' ) as PriceInUSD,
@Semantics.currencyCode
@ObjectModel.text.association: '_CurrencyText'
CurrencyCode,
@Search.defaultSearchElement: true
@Search.fuzzinessThreshold: 0.90
Memo,
Status,
LastChangedAt,
/* Associations */
//DMO/I_Travel_U
_Agency,
_Booking,
_Currency,
_Customer,
_CurrencyText
}
At the moment, your application is a simple list. It would be nice to click on a row, i.e. a travel, and get more details in a separate page, known as an object page. Later you can add details from other CDS entities using associations.
For more information on object pages, see SAP Help Portal: Defining UI Annotations
-
First add the page itself. Add the following annotation to your metadata extension, just after the opening curly bracket:
@UI.facet: [ { id: 'Travel', purpose: #STANDARD, type: #IDENTIFICATION_REFERENCE, label: 'Travel', position: 10 } ]
-
You then specify which elements you want to include in the object page. Since the facet type is
#IDENTIFICATION_REFERENCE
, you use the identification annotation, so that the complete annotation plus element now looks like this:@UI: { lineItem: [ { position: 20, label: 'Agency', importance: #HIGH } ], identification:[ { position: 10, label: 'Travel' } ], selectionField: [{position: 20 }] } TravelID;
-
Add the following to the other elements, so that your metadata extension looks like this:
@UI: { lineItem: [ { position: 20, label: 'Agency', importance: #HIGH } ], identification: [ { position: 20 } ], selectionField: [{position: 20 }] } AgencyID; @UI: { lineItem: [ { position: 30, label: 'Customer', importance: #HIGH } ] ,identification: [ { position: 30 } ] ,selectionField: [ { position: 30 }] } CustomerID; @UI: { lineItem: [ { position: 40 } ], identification: [ { position: 40 } ], selectionField: [ { position: 40 }] } BeginDate; @UI: { lineItem: [ { position: 50 } ], identification: [ { position: 50 } ] ,selectionField: [ { position: 50 }] } EndDate; @UI: { lineItem: [ { position: 60 } ], identification: [ { position: 50 } ] } TotalPrice;
-
Finally, add a header to your object page, just after the layer annotation (before the
annotate view...
statement):@UI: { headerInfo: { typeName: 'Travel', typeNamePlural: 'Travels', title: { type: #STANDARD, label: 'Travel', value: 'TravelID' } } }
-
Test your object page in the Fiori Elements preview. It should look roughly like this:
You will now add more information to the object page by creating:
- A CDS view for bookings
- An association from Travel to Booking
- Adding a second UI facet to the travel metadata extension
-
In the Package Explorer, select Data Definition, then choose New Data Definition from the context menu.
-
Enter the following:
- Name =
Z_C_BOOKING_XXX
- Description =
Consumption view from /DMO/I_BOOKING_U
- Referenced Object =
/DMO/I_BOOKING_U
- Name =
-
Choose the same transport request, then choose Next. Do not choose Finish.
-
Finally, choose Use template then choose Define view. Then choose Finish.
Your CDS view appears in a new editor.
-
Change the
sqlViewName
, e.g. toZC_BOOK_XXX
. -
Change the
@AccessControl.authorizationCheck:
to#NOT_REQUIRED
.
-
Add semantic annotations as follows:
@Semantics.amount.currencyCode: 'Currency_Code' FlightPrice as Flight_Price, @Semantics.currencyCode: true CurrencyCode as Currency_Code,
-
Format, save, and activate the CDS entity (**
Shift+F1, Ctrl+S, Ctrl+F3
**).
-
First, allow metadata extensions to your CDS entity by adding the following annotation just after the
@EndUserText.label: 'Consumption view from /DMO/I_BOOKING_U'
annotation:@Metadata.allowExtensions: true
-
In the Package Explorer, select the CDS entity
Z_C_booking_XXX
, then choose New Metadata Extension from the context menu. -
Enter a name
Z_C_booking_XXX
and description Metadata forZ_C_booking_XXX
; select the transport request and choose Finish., -
In the editor, enter the following code:
@Metadata.layer: #CORE annotate view Z_C_BOOKING_XXX with { @UI: { lineItem: [ { position: 10, importance: #HIGH } ], identification: [ { position: 10 } ] } BookingID; @UI: { lineItem: [ { position: 20, importance: #HIGH } ], identification: [ { position: 20 } ] } BookingDate; @UI: { lineItem: [ { position: 30, importance: #HIGH } ], identification: [ { position: 30 } ] } AirlineID; @UI: { lineItem: [ { position: 40, importance: #HIGH } ], identification: [ { position: 40 } ] } ConnectionID; @UI: { lineItem: [ { position: 50, importance: #HIGH } ], identification: [ { position: 50 } ] } FlightDate; @UI: { lineItem: [ { position: 60, importance: #MEDIUM } ], identification: [ { position: 60 } ] } Flight_Price; }
-
Format, save, and activate the metadata extension (**
Shift+F1, Ctrl+S, Ctrl+F3
**).
-
In your CDS view
Z_C_travel_XXX
, add an association to this booking view:association [0..*] to Z_C_booking_XXX as _booking on $projection.TravelID = _Booking.TravelId
-
Add the association to the field list.
-
Also, add the entity
Z_C_booking_XXX
to the service definitionZ_EXPOSE_travel_XXX
:
@EndUserText.label: 'Expose travel Service XXX'
define service Z_EXPOSE_travel_005 {
expose Z_C_travel_005 as Travel;
expose Z_C_booking_005 as Booking;
}
-
Check the service binding. It should now include a
to_Booking
association, like this: -
Format, save, and activate (**
Shift+F1, Ctrl+S, Ctrl+F3
**).
-
Before the square bracket, insert a comma after the Travel facet, then insert the Booking facet to the Travel metadata extension:
@UI.facet: [ { id: 'Travel', purpose: #STANDARD, type: #IDENTIFICATION_REFERENCE, label: 'Travel', position: 10 } , { id: 'Booking', purpose: #STANDARD, type: #LINEITEM_REFERENCE, label: 'Booking', position: 20, targetElement: '_Booking'} ]
-
Now specify which fields from Booking you want to include in the object page, again using an
identification
annotation as follows:@UI: { lineItem: [ { position: 10, importance: #HIGH } ], identification: [ { position: 10 } ] } BookingID; @UI: { lineItem: [ { position: 20, importance: #HIGH } ], identification: [ { position: 20 } ] } BookingDate; @UI: { lineItem: [ { position: 30, importance: #HIGH } ], identification: [ { position: 30 } ] } AirlineID; @UI: { lineItem: [ { position: 40, importance: #HIGH } ], identification: [ { position: 40 } ] } ConnectionID; @UI: { lineItem: [ { position: 50, importance: #HIGH } ], identification: [ { position: 50 } ] } FlightDate; @UI: { lineItem: [ { position: 60, importance: #MEDIUM } ], identification: [ { position: 60 } ] } Flight_Price;
- Test your new facet in the Fiori Elements preview. It should look like this:
You can also display information from another entity using an association.
-
Add an association from Booking to Connection.
association [1..1] to /DMO/I_Connection as _Connection on $projection.ConnectionId = _Connection.ConnectionID
-
You will get a warning. If you choose Problem Description, you will see that this warning can be hidden, by adding the following pseudo-comment:
/*+[hideWarning] { "IDS" : [ "CARDINALITY_CHECK" ] }*/
-
Now add the following two elements to the entity
Z_C_BOOKING_XXX
:@Semantics.quantity.unitOfMeasure: 'DistanceUnit' _Connection.Distance as Distance, @Semantics.unitOfMeasure: true _Connection.DistanceUnit as DistanceUnit,
-
Optional: Test your Fiori Elements preview again. It should look like this:
- Add the following code, immediately after the element
DistanceUnit
:case when _Connection.Distance >= 2000 then 'long-haul flight' when _Connection.Distance >= 1000 and _Connection.Distance < 2000 then 'medium-haul flight' when _Connection.Distance < 1000 then 'short-haul flight' else 'error' end as Flight_type,
- Also, make sure that the distance is in kilometers, by adding this code after the select list:
where _Connection.DistanceUnit = 'KM'
-
Format, save, and activate the CDS view.
-
Test your Fiori Elements preview again. It should look like this:
More Information
-
Blog post: From Open SQL Joins to CDS Associations
-
SAP Help Portal: Defining UI Annotations
Next Steps
-
Step 1: Add value help
-
Step 2: Add text associations
-
Step 3: Merge two fields
-
Step 4: Add currency conversion
-
Step 5: Check code for CDS view
-
Step 6: Test yourself
-
Step 7: Create object page
-
Step 8: Create CDS view for booking
-
Step 9: Add annotations
-
Step 10: Create metadata extension
-
Step 11: Add association from Travel to Booking
-
Step 12: Add Booking information to object page
-
Step 13: Add association from Booking to Connection
-
Step 14: Add CASE statement
- Back to Top