- Design / Prototype
- Create Dictionary Objects
- Core Data Services (CDS)
- Business Service
- Business Object Behavior
- Create a Fiori App
- Source (GitHub) for Data Model/Behaviour/Service
- Source (GitHub) for User Interface (Fiori Elements App)
We will define the Interface Views for the Phone Book App using CDS (Core Data Services) in ADT (ABAP Development Tools)
Data Model
We will be creating CDS View Entities for Phone Book. There will be one root node Contacts (Phone Book Head) and one child node Phone Numbers (Phone Book Item).
SAP recommends using CDS view entities instead of DDIC-based view due to technical improvements, such as performance at activation, and so on.
Description | CDS DDIC-Based Views | CDS View Entities |
---|---|---|
Optimized CDS activation | The CDS entity, CDS DDIC-based view, and database view need to be activated. | Only the CDS entity and the respective database view on SAP HANA need to be activated. Consequently, the performance of the activation runs faster. Simplified handling of CDS extends |
Syntax and annotation checks | Simple checks | Stricter checks that indicate critical situations more explicitly |
Client handling | Based on different algorithms. Controlled using the ClientHandling.type and ClientHandling.algorithm annotations | Automatized for complete transparency No annotation allowed for client handling |
Database object | View / table function | View |
CDS-managed DDIC view in ABAP Dictionary | Creation upon activation | No CDS-managed DDIC view is generated upon activation |
Naming convention | Three names for the CDS object, CDS entity, and the CDS-managed DDIC view on SAP HANA | One name for the CDS object, CDS entity, and database view on SAP HANA |
Phone Book Header Interface View
CDS Root view entity ZINTLRA_I_PB_HEAD is created with composition (child) ZINTLRA_I_PB_ITEM
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Phone Book Header Interface View'
define root view entity ZINTLRA_I_PB_HEAD as select from zintlra_pb_d_hdr
composition [0..*] of ZINTLRA_I_PB_ITEM as _item
association [1..1] to ZINTLRA_I_PB_USER as _owner
on $projection.PbOwner = _owner.OwnerID
association [1..1] to ZINTLRA_I_PB_TAG as _tagText
on $projection.PbTagCode = _tagText.PbTagCode
and _tagText.PbLanguage = $session.system_language
{
key pb_uuid as PbUuid,
pb_id as PbId,
@Semantics.user.createdBy: true
pb_owner as PbOwner,
_owner.FullName as PbOwnerName,
pb_tag_code as PbTagCode,
_tagText.PbTagText as PbTagText,
pb_first_name as PbFirstName,
pb_last_name as PbLastName,
concat_with_space(pb_first_name, pb_last_name, 1) as PbContactName,
@Semantics.systemDateTime.createdAt: true
pb_created_at as PbCreatedAt,
@Semantics.systemDateTime.lastChangedAt: true
pb_changed_at as PbChangedAt,
@Semantics.eMail.address: true
pb_email_id as PbEmailId,
pb_favourite as PbFavourite,
/* Associations */
_item,
_owner,
_tagText
}where pb_owner = $session.user
Phone Book Item Interface View
CDS view entity ZINTLRA_I_PB_ITEM is created with association to parent ZINTLRA_I_PB_HEAD
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Phone Book Items Interface View'
define view entity ZINTLRA_I_PB_ITEM as select from zintlra_pb_d_itm
association to parent ZINTLRA_I_PB_HEAD as _hdr
on $projection.PbUuid = _hdr.PbUuid
association [1..1] to ZINTLRA_I_PB_CAT as _catText
on $projection.PbCategory = _catText.PbCategory
and _catText.PbLanguage = $session.system_language
{
key pb_item_uuid as PbItemUuid,
pb_uuid as PbUuid,
pb_id as PbId,
pb_item_id as PbItemId,
pb_category as PbCategory,
@Semantics.text: true
_catText.PbCategoryText,
pb_telephone as PbTelephone,
@Semantics.systemDateTime.createdAt: true
pb_created_at as PbCreatedAt,
@Semantics.systemDateTime.lastChangedAt: true
pb_changed_at as PbChangedAt,
pb_default as PbDefault,
/* Associations */
_hdr,
_catText
}
Phone Book User View
CDS for User Details
@AbapCatalog.sqlViewName: 'ZINTIPBUSER'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Phone Book User View'
define view ZINTLRA_I_PB_USER
as select from usr21 as _User
association [0..1] to adrp as _Person on _Person.persnumber = $projection.Person
and _Person.persnumber <> ''
{
@ObjectModel.text.element : 'UserDescription'
@Semantics.contact.type: #PERSON
key _User.bname as OwnerID,
_User.persnumber as Person,
@Semantics.name.givenName: true
_Person.name_first as FirstName,
@Semantics.name.familyName: true
_Person.name_last as LastName,
@Semantics.name.fullName: true
cast(coalesce( _Person.name_text , _User.techdesc ) as ad_namtext preserving type ) as FullName
}
Phone Book Tags View
@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Phone Book Tags'
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.usageType:{
serviceQuality: #X,
sizeCategory: #S,
dataClass: #MIXED
}
define view entity ZINTLRA_I_PB_TAG as select from zintlra_pb_d_tag {
key pb_tag_code as PbTagCode,
key pb_spras as PbLanguage,
pb_tag_text as PbTagText
}
Phone Book Contact Category View
@AbapCatalog.sqlViewName: 'ZINTIPBCAT'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@VDM.viewType: #BASIC
@EndUserText.label: 'Contact Category View'
define view ZINTLRA_I_PB_CAT as select from zintlra_pb_d_cnt {
key pb_category as PbCategory,
key pb_spras as PbLanguage,
pb_category_text as PbCategoryText
}
Data Model Projection
CDS Projection View
A CDS projection view is a special view that is based on another CDS view and exposes only a subset of elements of the projected entity.
Use
A projection view enables you to expose a subset of data from an underlying data model, for example, to be used in an OData service. It is a direct projection of an underlying CDS view without parameters and exposes a subset of elements of the projected entity, which are defined in the list of elements.
In a business application, a projection view allows to restrict access to, denormalize, and fine-tune the underlying data model.
Use Cases
As an application developer, you want to, for example, …
– contemplate a subset of the business object as a business service.
– alias or rename the projected subset.
– omit or hide chosen elements or associations
Source
Phone Book Item Projection View
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 annotated element. name: Specifies the entity which contains the element that provides the value help. element: Specifies the element in the entity referenced in the name that provides the value help for the annotated element. @Search.defaultSearchElement: true Specifies that the element is to be considered in a freestyle search (for example a SELECT…) where no columns are specified. Usually, such a search must not operate on all elements – for performance reasons, and because not all elements (e.g. internal keys) do qualify for this kind of access. @ObjectModel.text.element: Establishes the conjunction of a field with its descriptive language-independent texts. CDS ANNOTATIONS
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Phone Book Item Consumption View'
@Search.searchable: true
@Metadata.allowExtensions: true
define view entity ZINTLRA_C_PB_ITEM as projection on ZINTLRA_I_PB_ITEM {
key PbItemUuid,
PbUuid,
PbId,
PbItemId,
@Search.defaultSearchElement: true
@Consumption.valueHelpDefinition: [{ entity: { name: 'ZINTLRA_I_PB_CAT', element: 'PbCategory' } }]
@ObjectModel.text.element: ['PbCategoryText']
PbCategory,
PbCategoryText,
@Search.defaultSearchElement: true
PbTelephone,
PbCreatedAt,
PbChangedAt,
PbDefault,
/* Associations */
_catText,
_hdr:redirected to parent ZINTLRA_C_PB_HEAD
}
Phone Book Header Projection View
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Phone Book Header Consumption View'
@Search.searchable: true
@Metadata.allowExtensions: true
@ObjectModel.semanticKey: ['PbUuid']
define root view entity ZINTLRA_C_PB_HEAD
as projection on ZINTLRA_I_PB_HEAD
{
@Search.defaultSearchElement: true
key PbUuid,
PbId,
PbOwner,
PbOwnerName,
@Consumption.valueHelpDefinition: [{ entity: { name: 'ZINTLRA_I_PB_TAG', element: 'PbTagCode' } }]
@ObjectModel.text.element: ['PbTagText']
@Search.defaultSearchElement: true
PbTagCode,
PbTagText,
@Search.defaultSearchElement: true
PbFirstName,
@Search.defaultSearchElement: true
PbLastName,
PbContactName,
PbCreatedAt,
PbChangedAt,
PbEmailId,
PbFavourite,
/* Associations */
_item: redirected to composition child ZINTLRA_C_PB_ITEM,
_owner
}
Metadata Extension
Metadata extensions 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
The metadata of CDS entities is not extensible by default.
To use a metadata extension for a CDS entity, you have to consider the following conditions:
- 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.
- In the metadata extension, you have to define the name of the CDS entity to be annotated in the annotate view statement.
- In the Switch Framework, metadata extensions are switchable.
Advantages
You can benefit from the following advantages using metadata extensions:
- 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.
- 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.
- 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.
Phone Book Header Extension
UI.headerinfo
Annotations belonging to UI.headerInfo describe an entity, its title and an optional short description, the name of its entity in singular and plural form, and optional image URLs for the individual entity.
UI.lineitem
Annotations belonging to UI.lineItem represent an ordered collection of data fields that are used to represent data from multiple data instances in a table or a list.
UI.identification
Annotation belonging to UI.identification represents an ordered collection of specific data fields that together with headerInfo identifies an entity to an end user. This annotation is displayed in the General Information section in the body of the object view floorplan of an item, for example.
UI.selectionField
Annotations belonging to UI.selectionField allow filtering a list of data. UI.selectionField annotations are usually used in an initial page floorplan as a filter bar.
UI.facet
Is used to manipulate the layout of the Object Page
UI.presentationVariant.sortOrder
Annotations belonging to UI.presentationVariant.sortOrder represent a collection of sorting parameters that can be provided inline or by a reference to a Common.SortOrder annotation (syntax is identical to AnnotationPath).
UI.presentationVariant.visualizations
Annotations belonging to UI.presentationVariant.visualizations represent a collection of available visualization types.
The following types are supported:
– UI.lineItem
– UI.chart
– UI.dataPoint
{ type: #FOR_ACTION, dataAction: ‘<action_name>’, label: ‘<action_button_label>’ }
For exposing actions to the users
Source
@Metadata.layer: #CORE
@UI:{
headerInfo: {
typeName: 'Contact',
typeNamePlural: 'Contacts',
title: {
type: #STANDARD,
label: 'Contact',
value: 'PbContactName'
}
},
presentationVariant: [{
sortOrder: [{
by: 'PbUuid',
direction: #DESC
}],
visualizations: [{
type: #AS_LINEITEM
}]
}]
}
annotate view ZINTLRA_C_PB_HEAD
with
{
@UI.facet: [{
id:'Contact',
purpose:#STANDARD,
type: #IDENTIFICATION_REFERENCE,
label: 'Contact',
position: 10
},
{
id:'PhoneNumber',
purpose:#STANDARD,
type: #LINEITEM_REFERENCE,
label: 'Phone Numbers',
position: 20,
targetElement: '_item'
}]
@UI.hidden: true
PbOwner;
@UI.hidden: true
PbOwnerName;
@UI.hidden: true
PbId;
@UI: {
lineItem: [ { position: 10 } ],
identification: [ { position: 10 } ],
selectionField: [ { position: 10 } ]
}
PbTagCode;
@UI: {
lineItem: [ { position: 20 } ],
identification: [ { position: 20 } ],
selectionField: [ { position: 20 } ]
}
PbFirstName;
@UI: {
lineItem: [ { position: 30 } ],
identification: [ { position: 30 } ],
selectionField: [ { position: 30 } ]
}
PbLastName;
@UI.hidden: true
PbCreatedAt;
@UI.hidden: true
PbChangedAt;
@UI: {
lineItem: [ { position: 40 } ],
identification: [ { position: 40 } ]
}
PbEmailId;
@UI: {
lineItem: [ { position: 50 },
{ type: #FOR_ACTION, dataAction: 'setFavourite', label: 'Set Favourite' },
{ type: #FOR_ACTION, dataAction: 'removeFavourite', label: 'Not a Favourite' }
],
identification: [ { position: 50 },
{ type: #FOR_ACTION, dataAction: 'setFavourite', label: 'Set Favourite' },
{ type: #FOR_ACTION, dataAction: 'removeFavourite', label: 'Not a Favourite' }
],
selectionField: [ { position: 50 } ]
}
PbFavourite;
/* Associations */
@UI.selectionField: [{ element: '_item.PbTelephone', position: 60 }]
_item;
}
Phone Book Item Extension
@Metadata.layer: #CORE
@UI:{
headerInfo:{
typeName: 'Phone Number',
typeNamePlural: 'Phone Numbers',
title:{
type: #STANDARD,
value: 'PbCategoryText'
}
}
}
annotate view ZINTLRA_C_PB_ITEM
with
{
@UI.facet: [ {
id: 'Booking',
purpose: #STANDARD,
type: #IDENTIFICATION_REFERENCE,
label: 'Phone Number',
position: 10
} ]
@UI.hidden: true
PbItemUuid;
@UI.hidden: true
PbUuid;
@UI.hidden: true
PbId;
@UI.hidden: true
PbItemId;
@UI: {
lineItem: [ { position: 10 } ],
identification: [ { position: 10 } ]
}
PbCategory;
@UI: {
lineItem: [ { position: 20 } ],
identification: [ { position: 20 } ]
}
PbTelephone;
@UI: {
lineItem: [ { position: 30 },
{ type: #FOR_ACTION, dataAction: 'setDefault', label: 'Set Default' }
],
identification: [ { position: 30 },
{ type: #FOR_ACTION, dataAction: 'setDefault', label: 'Set Default' }
]
}
PbDefault;
@UI.hidden: true
PbCreatedAt;
@UI.hidden: true
PbChangedAt;
}