第 109 页 / 共 465 页
3.4 Service Adaptation Description Language
Figure 3.16 Adding a New OData Service to the Service Catalog
3.4 Service Adaptation Description Language
One of the core technologies enabling the ABAP programing model for SAP Fiori is
the Service Adaptation Description Language (SADL). It provides two main function-
alities in this context:
(cid:2) At design time, SADL supports the model-based creation of an OData service based
on a CDS data model.
(cid:2) At runtime, the OData runtime delegates incoming requests for OData entities to
the SADL adapter, which dynamically generates SQL SELECT statements to select
the business data via CDS views or further delegates the requests to the transac-
tional BOPF runtime if write access is required.
With this, SADL supports two of the three phases required for developing an OData
service:
(cid:2) Data model definition (supported by SADL)
(cid:2) Service implementation (supported by SADL)
(cid:2) Service maintenance
109
第 110 页 / 共 465 页
3 ABAP Programing Model for SAP Fiori
3.4.1 Data Model Definition Phase
The aim of this OData service development phase is to provide potential clients of the
service with information about the service’s shape, for instance, the structure of its
entities, their relationships, and the supported operations. This information is pro-
vided in the form of a service metadata document in Extensible Markup Language
(XML). In the data model definition phase, SADL creates a mapping of CDS entities to
an OData Entity Data Model (EDM) and populates the MPC of the OData implementa-
tion with information derived from the CDS model structure. Additionally, CDS view
field data types are mapped to EDM primitive data types; for instance, the ABAP dic-
tionary built-in type DATS is mapped to the EDM.DateTime data type. Moreover, if trans-
actional processing is enabled for CDS entities via the creation of a BOPF business
object, BOPF actions will appear as OData function imports in the service metadata
document. Table 3.2 provides an overview of the mappings from CDS concepts to
OData concepts performed by SADL.
CDS OData
CDS view (DDL) EDM entity
CDS associations EDM association
CDS view field data type EDM primitive data type
BOPF actions Function import
Table 3.2 Mappings between CDS Data Model Concepts and OData EDM Concepts
Figure 3.17 shows how the service metadata document will look for the simple sce-
nario introduced in Chapter 1. As you remember, the purchase document CDS view
(Z_PurchasingDocumentDDL) had an association to the purchase document items view
(Z_PurchasingDocumentItemDDL). Both views now appear as OData entity types in the
OData service’s metadata document, including the information about the associa-
tion between the two entities and their cardinalities. Which operations an entity sup-
ports is indicated by the sap:creatable, sap:updatable, and sap:deletable attributes
of the EntitySet element. In the following example, you can see that the service
doesn’t support any write access at all, as we haven’t enabled the transactional run-
time for our CDS model by generating a BOPF business object. Thus, the service only
supports read access via HTTP GET entity requests. As already mentioned, the meta-
data file of an OData service can be requested using the $metadata path, /sap/opu/
odata/sap/<OData_service_name>/$metadata.
110
| CDS | OData |
|---|---|
| CDS view (DDL) | EDM entity |
| CDS associations | EDM association |
| CDS view field data type | EDM primitive data type |
| BOPF actions | Function import |
第 111 页 / 共 465 页
3.4 Service Adaptation Description Language
Figure 3.17 XML Service Metadata Document of the Simple CDS Scenario from Chapter 1
Exposed as an OData Service
3.4.2 Service Implementation Phase
In the previous data model definition phase, SADL maps the CDS data model to an
OData EDM and creates a static service definition. At runtime, SADL also takes care of
processing the OData requests performed by clients. The OData runtime delegates
OData requests to the generic SADL query engine, which generates SQL SELECTS on
CDS views based on the request parameters ($select, $top, $filter, etc.) and the
requested OData entity.
An incoming OData request for the standard purchase order basic view entity might
look like Listing 3.2.
GET I_PurchaseOrderEntity?$select=
PurchaseOrder,PurchaseOrderType,PurchasingOrganization,PurchasingGroup,Purchas
eOrderDate&$top=10&$orderby=PurchaseOrderDate asc&$filter=
111
第 112 页 / 共 465 页
3 ABAP Programing Model for SAP Fiori
( PurchaseOrderDate ge datetime'2018-01-
01T00:00:00' and PurchaseOrderDate le datetime'2018-12-31T00:00:00')
Listing 3.2 OData GET Request for the I_PurchaseOrderEntity OData Entity
The SADL framework will then transparently transform this request into an SQL
SELECT statement on the I_PurchaseOrder CDS view (Listing 3.3).
SELECT
PurchaseOrder,
PurchaseOrderType,
PurchasingOrganization,
PurchasingGroup,
PurchaseOrderDate
FROM
I_PurchaseOrder
WHERE
PurchaseOrderDate GE '20180601'
AND PurchaseOrderDate LE '20180601'
ORDERBY
PurchaseOrderDate ASCENDING
UP TO 10 ROWS
Listing 3.3 Generated SQL SELECT for the OData GET Request
When you compare the OData request and the generated SQL statement, you can see
that OData queries can easily be pushed down to a relational database as OData
already resembles SQL, and all OData parameters can be mapped to a certain part of
the SQL SELECT statement. This property makes OData the perfect candidate for
exposing business entities over HTTP because easy transformation of HTTP requests
to SQL SELECT statements promotes the Code-to-Data paradigm of SAP HANA and
prevents unnecessary data processing on the ABAP server. Table 3.3 shows the map-
pings between OData parameters and SQL query parts.
OData Parameter SQL
$select SELECT
$top UP TO n ROWS
Table 3.3 Mapping between OData Parameters and Corresponding Parts of an SQL SELECT
Statement
112
| OData Parameter | SQL |
|---|---|
| $select | SELECT |
| $top | UP TO n ROWS |
第 113 页 / 共 465 页
3.5 Business Object Processing Framework
OData Parameter SQL
$orderby ORDERBY
$filter WHERE
Table 3.3 Mapping between OData Parameters and Corresponding Parts of an SQL SELECT
Statement (Cont.)
3.5 Business Object Processing Framework
The Business Object Processing Framework (BOPF) is an ABAP framework that consti-
tutes the transactional runtime of an application in the ABAP Programming Model
for SAP Fiori. As soon as an application requires write actions such as CUD, a BOPF
business object must be generated from the CDS data model, which will take over the
transactional part of the app. Currently, four transactional scenarios are supported,
as discussed in the following subsections.
3.5.1 Read-Only Application with Quick Actions
In this case, you don’t want to enable full create, write, and delete access but only
enable a quick action, for instance, for changing the status of the business object. A
BOPF business object for this scenario can be generated by annotating the root view
of the CDS model with annotations on the header level as shown in Listing 3.4.
@ObjectModel: {
transactionalProcessingEnabled: true,
compositionRoot: true,
writeActivePersistence: '<SQL View>',
createEnabled: false,
updateEnabled: false,
deleteEnabled: false
}
Listing 3.4 Required Annotations for Generating a BOPF Business Object to Implement
Quick Actions
(Re)activation of the view will lead to the generation of a BOPF business object, and
Quick Actions can be implemented in ABAP for the respective BOPF node. We also
113
| OData Parameter | SQL |
|---|---|
| $orderby | ORDERBY |
| $filter | WHERE |
第 114 页 / 共 465 页
3 ABAP Programing Model for SAP Fiori
must provide an active persistence using the writeActivePersistence annotation.
However, in this case, because we don’t allow standard (CUD) access, it will only be
used for field mappings between CDS and BOPF.
Note
When exposing a CDS view as an OData service using Auto-Exposure or the RDS sce-
nario, SADL takes the createEnabled, updateEnabled, and deleteEnabled CDS anno-
tations into account and maps them to OData entity set attributes. For instance, if
the CDS view doesn’t enable write access or doesn’t have a linked BOPF business
object at all, the respective OData entity set will have the attributes sap:creatable=
”false”, sap:updatable=”false”, and sap:deletable=”false”.
3.5.2 New Application without Draft
If we also want to enable standard generic CUD access for our application, we must
set the createEnabled, updateEnabled, and deleteEnabled annotations to true (Listing
3.5). Furthermore, we must provide the database table in which the data must be per-
sisted in using the writeActivePersistence annotation.
@ObjectModel: {
transactionalProcessingEnabled: true,
compositionRoot: true,
writeActivePersistence: '<ActivePersistenceName>',
createEnabled: true,
updateEnabled: true,
deleteEnabled: true
}
Listing 3.5 Required Annotations for Full CUD BOPF Support
In this case, BOPF will generically handle CUD operations. If we want to enhance the
standard generic transaction logic, we can provide BOPF actions, validations, or
determinations for the respective node of the BOPF business object. However, if we
want to reuse existing legacy ABAP CUD implementations containing complex busi-
ness logic, the next scenario is better suited.
114
| Note When exposing a CDS view as an OData service using Auto-Exposure or the RDS sce- nario, SADL takes the createEnabled, updateEnabled, and deleteEnabled CDS anno- tations into account and maps them to OData entity set attributes. For instance, if the CDS view doesn’t enable write access or doesn’t have a linked BOPF business object at all, the respective OData entity set will have the attributes sap:creatable= |
| ”false”, sap:updatable=”false”, and sap:deletable=”false”. |
第 115 页 / 共 465 页
3.5 Business Object Processing Framework
3.5.3 Draft-Enabled Application
In this scenario, data isn’t immediately written to the standard active database tables
but is stored in a draft table. This scenario is very well suited for legacy applications
that already consist of database tables and ABAP CUD code, including complex busi-
ness logic. We can enable the old database tables for SAP HANA optimized read access
by providing CDS views on top of the legacy database tables and still reuse the legacy
ABAP code when activating a draft. Activating in this context means transferring the
data from the intermediary draft table to the actual table. To do this, the BOPF busi-
ness object root node will provide an adapter (/bobf/if_frw_draft~copy_draft_to_
active_entity) that must be implemented by the developer and maps the draft repre-
sentation of the data to the legacy signature of the ABAP code to write the data into
the legacy database tables. The required annotations for generating the draft infra-
structure are shown in Listing 3.6.
@ObjectModel: {
transactionalProcessingEnabled: true,
compositionRoot: true,
draftEnabled: true;
writeDraftPersistence: '<DraftPersistenceName>',
createEnabled: true,
updateEnabled: true,
deleteEnabled: true
}
Listing 3.6 Required Annotations for Generating the BOPF Draft Infrastructure for a Legacy
Application with an Existing Persistence
3.5.4 New Application with Draft
In this scenario, we provide new tables for draft and active entities (Listing 3.7). As in
the previous scenario, data will be stored in intermediary draft tables and only writ-
ten to the active persistence on explicit activation of the entity. However, in this sce-
nario, BOPF will completely take over the transactional processing. We can only
enhance the data processing by adding BOPF actions, validations, or determinations
to the respective nodes of the BOPF object. This scenario is only suited for new appli-
cations. If legacy tables and ABAP CUD code will be reused, this scenario isn’t the right
choice.
115
第 116 页 / 共 465 页
3 ABAP Programing Model for SAP Fiori
@ObjectModel: {
transactionalProcessingEnabled: true,
compositionRoot: true,
draftEnabled: true;
writeDraftPersistence: '<DraftPersistenceName>',
writeActivePersistence: '<ActivePersistenceName>'
createEnabled: true,
updateEnabled: true,
deleteEnabled: true
}
Listing 3.7 Required Annotations for Generating the BOPF Draft Infrastructure for a New
Application
3.6 SAP Fiori
The open access to backend business data via OData and SAP Gateway enables the use
of modern non-ABAP UI technologies for displaying and interacting with business
data. The UI of applications developed using the ABAP programming model for SAP
Fiori is therefore completely based on the SAPUI5 framework, which implements the
SAP Fiori design. The UI part of applications is usually implemented using the cloud-
based SAP Web IDE and is either based on SAP Fiori elements applications or freestyle
applications. SAP Fiori elements applications, for instance, the list report and object
page templates or floorplans, adapt their layouts based on the OData service’s meta-
data and UI annotations defined in CDS views or their respective metadata exten-
sions. Therefore, SAP Fiori elements templates significantly reduce the necessary
frontend SAPUI5 JavaScript code to a minimum and increase developer productivity
significantly by still providing flexibility using predefined extension points in the
frontend.
Additionally, transparent to the developer, the SAP Fiori elements applications
implement the necessary CRUD request handling for read-only, draft-enabled, and
non-draft-enabled applications, depending on which BOPF scenario has been anno-
tated, generated, and implemented in the backend. Freestyle applications, in contrast
to SAP Fiori elements, provide the frontend developer with full flexibility over the UI
design and logic but require a lot of effort in the development phase. The UI layout
and its controls must be declared manually by the developer, and the necessary
SAPUI5 JavaScript logic must be implemented. Therefore, it’s not recommended to
116
第 117 页 / 共 465 页
3.7 Summary
use complex draft-enabled BOPF scenarios with freestyle applications because the
orchestration of the necessary requests might become too complicated. Moreover,
another risk when developing freestyle applications is the violation of SAP Fiori
design guidelines. Consequently, only use freestyle applications when the required
UI design isn’t realizable using one of the SAP Fiori elements floorplans.
3.7 Summary
In this chapter, we gave you an overview of the ABAP programing model for SAP Fiori
and its associated technologies. We started with CDS, which are at the center of any
application development for SAP S/4HANA. They are the foundation for all applica-
tion types and can be configured for different application types using domain-spe-
cific UIs, analytics, search annotations, or transactional annotations. Next, we looked
at SAP Gateway and OData as the technologies enabling easy network-based access to
business data stored in SAP NetWeaver backend systems. Then we explored SADL
and how it supports providing model-based read and transactional access to CDS
entities via OData. The BOPF constitutes the transactional runtime of the ABAP pro-
gramming model for SAP Fiori and enables ABAP-based CUD operations for data
models based on CDS views. It provides several scenarios for different application
requirements, which we briefly listed and described.
117
第 118 页 / 共 465 页
第 119 页 / 共 465 页
PART II
Developing Applications for SAP S/4HANA
第 120 页 / 共 465 页
第 121 页 / 共 465 页
Chapter 4
Developing an SAP Fiori Elements
List Report and Object Page
In this chapter, you’ll learn to create your first SAP Fiori elements
applications: a list report and object page. We’ll illustrate the end-to-
end development process in detail with step-by-step instructions.
You’ll create database tables and Core Data Services (CDS) views, gen-
erate a Business Object Processing Framework (BOPF) object for trans-
actional processing, add user interface (UI) elements, and create an
OData service—building both the backend and the frontend of the
application.
We’ll use the business scenario and design developed in Chapter 2, Section 2.4.3, to
create an application for managing purchase documents. As a reminder, the applica-
tion design consisted of a list report displaying purchase documents in a table and an
object page providing detailed information for a purchase document, including its
individual purchase document items. Moreover, some purchase documents might
require approval, which can be granted using a quick action.
Using this business scenario, we’ll provide you with an end-to-end development
guide for developing list report and object page applications based on the ABAP pro-
gramming model for SAP Fiori.
4.1 Core Data Services Views
In this section, you’ll learn how to create a layered CDS data model according to the
SAP S/4HANA Virtual Data Model (VDM) modeling guidelines, including unit tests
for calculated field values using ABAP Unit and the CDS Test Double Framework.
Before we can start the development, we first must install the ABAP development
121
第 122 页 / 共 465 页
4 Developing an SAP Fiori Elements List Report and Object Page
tools because Eclipse is the standard integrated development environment (IDE) for
developing CDS views and modern ABAP code. We then start the development of the
app from the bottom up by first introducing the data model and its database tables.
Based on this, we’ll create several layers of CDS views beginning with the basic inter-
face layer as a simple projection layer on top of the database tables. Using the basic
interface view layer as the basis, we’ll incrementally add more application-specific
views and calculations, including tests.
4.1.1 ABAP Development Tools in Eclipse
For developing state-of-the-art ABAP applications based on the ABAP programming
model for SAP Fiori, it’s no longer possible to use the classic ABAP Development
Workbench, accessible via Transaction SE80, because the development of CDS-based
data models isn’t supported with the old development tools anymore. Therefore,
developers must get a recent version of Eclipse, for instance, Eclipse Oxygen (IDE for
Java Developers) from the Eclipse Foundation’s website and subsequently install the
ABAP development tools frontend as an Eclipse plug-in. To do this, you must open
the Help menu of Eclipse and choose Install New Software (Figure 4.1).
Figure 4.1 Starting the ABAP Development Tools Installation Procedure in Eclipse
122
第 123 页 / 共 465 页
4.1 Core Data Services Views
This will open the Eclipse installation dialog. Next, you must add the ABAP develop-
ment tools update site as a new repository destination (Figure 4.2). The corresponding
ABAP development tools installation URL for the current Eclipse version is available
on the SAP Development Tools website at https://tools.hana.ondemand.com/#abap.
Figure 4.2 Adding the ABAP Development Tools in Eclipse Repository
To develop applications using the ABAP programming model for SAP Fiori, only the
ABAP development tools for SAP NetWeaver are required, so only select this software
package (Figure 4.3). Click Next, accept the terms of the license agreement, and click
on Finish. After the installation is done, Eclipse will require a restart.
123
第 124 页 / 共 465 页
4 Developing an SAP Fiori Elements List Report and Object Page
Figure 4.3 Selecting the ABAP Development Tools for SAP NetWeaver
To connect to a SAP NetWeaver ABAP backend server, you first must open the now
available ABAP Perspective by clicking on Window (cid:2) Perspective (cid:2) Open Perspective (cid:2)
Other… (cid:2) ABAP. From there, you can create an ABAP project that will establish the con-
nection to the backend server. Figure 4.4 shows how the ABAP project creation pro-
cess can be started by clicking on File (cid:2) New (cid:2) ABAP Project in the Eclipse menu bar. A
new project can be created in one of the following ways:
(cid:2) From a predefined SAP Logon system connection
(cid:2) By defining a manual system connection
(cid:2) By duplicating an existing system connection
124
第 125 页 / 共 465 页
4.1 Core Data Services Views
Figure 4.4 Creating an ABAP Project from the ABAP Perspective in Eclipse
Note
To enable your ABAP backend for using the ABAP development tools in Eclipse, see
the “Configuring ABAP Back-end for ABAP Development Tools” guide provided by SAP
at https://archive.sap.com/documents/docs/DOC-62593.
4.1.2 Introduction to the Data Model
The first step in any app development is the creation of a data model followed by the
creation of actual database tables for persisting transactional or master data. In the
next sections, we’ll therefore introduce the underlying data model of the app and cre-
ate the necessary database tables.
Entity Relationship Model
The conceptual data model of the app in the form of an Entity Relationship Model
(ERM) is shown in Figure 4.5. It consists of a purchase document entity type and a pur-
chase document item entity type. Purchase documents have a 0 to n relationship
to items, and items have a 1 to 1 relationship to documents, which constitutes a
parent-child relationship with documents being the parent nodes and items the child
nodes.
The purchase document entity has several attributes, including the overall docu-
ment status and priority of the purchase, as well as the responsible purchasing orga-
nization. The primary key of a purchase document is based on a single purchase
document ID. The purchase document item entity represents the actual items of the
125
| Note To enable your ABAP backend for using the ABAP development tools in Eclipse, see the “Configuring ABAP Back-end for ABAP Development Tools” guide provided by SAP |
| at https://archive.sap.com/documents/docs/DOC-62593. |
第 126 页 / 共 465 页
4 Developing an SAP Fiori Elements List Report and Object Page
purchase, including price and quantity. The primary key of a purchase document
item entity consists of an item ID and the purchase document ID, which references
the purchase document ID in the purchase document entity via a foreign key rela-
tionship.
Purchase …
Document
1 n Purchase
Purchase Document has
Document Item
Status Quantity
Purchase
Purchase
Purchasing Document Price
Priority … Document
Organization Item
Figure 4.5 Conceptual Data Model of the Application Depicted in the Form of an ERM
Database Tables
The foundation of any application in SAP S/4HANA is made up of the database tables
in which data is persisted in the SAP HANA database. New database tables can be cre-
ated in Eclipse using a source code editor available since SAP NetWeaver Application
Server for ABAP 7.52 SP 00 (SAP NetWeaver AS for ABAP). To persist the described pur-
chase document and purchase document item entities and their values on the data-
base, we need to create two separate database tables.
The following steps must be executed to create a transparent table in the ABAP Dic-
tionary:
1. Open the ABAP perspective in the ABAP development tools in Eclipse.
2. In the ABAP project, select the package node in which you want to create the table
via the Project Explorer view.
3. Open the context menu by right-clicking on the package, and select New (cid:2) Other
ABAP Repository Object (cid:2) Dictionary (cid:2) Database Table.
4. The database table creation wizard opens, and you must enter a Name and De-
scription (Figure 4.6). In our case, we’ll create a table for purchase documents called
ZPURCHDOCUMENT and a table for purchase document items called ZPURCHDOCITEM.
5. Finally, the database table source code editor opens, so you can now add fields to
the table and configure its properties.
126
第 127 页 / 共 465 页
4.1 Core Data Services Views
Figure 4.6 Database Table Creation Wizard
The programing language of the source code editor closely resembles the data defini-
tion language (DDL) of CDS. Metadata defined using annotations and technical prop-
erties, such as fields, is defined in an SQL-like syntax (Figure 4.7). On save or
activation, the actual persistence is updated. The source code displayed in the editor
isn’t a new transportable development object. All information is stored and retrieved
from the classic ABAP Dictionary. The source code definition of the database table for
persisting purchase documents is shown in Figure 4.7 and Listing 4.1.
Figure 4.7 The Table Editor Based on Source Code in Eclipse
127
第 128 页 / 共 465 页
4 Developing an SAP Fiori Elements List Report and Object Page
Using the editor based on source code in Eclipse, we can define technical as well as
semantic attributes of the table with the help of annotations. For instance, with the
@EndUserText.label annotation, we can provide meaningful and translatable labels
and descriptions for objects and fields. For fields, this annotation will only be consid-
ered if the field has no data element assigned; otherwise, the field label is taken from
the data element. For simplicity, we’ve only created a data element for the purchase-
document field (zpurchasedocumentdtel) as this is required for later referencing the
field via a foreign key annotation in the purchase document items table. The other
fields are typed using built-in ABAP types, for instance, abap.char(4).
The technical @AbapCatalog.enhancementCategory: #EXTENSIBLE_ANY annotation in the
header part of the table definition specifies that all structure and database compo-
nents and their enhancements may contain components whose data type can be of
any category. The #TRANSPARENT table category is the default category for database
tables, and, on activation, it leads to the creation of a database table on the database
as well as to the creation of an identical variant in the classic ABAP Dictionary. Deliv-
ery class #A indicates that the table is an application table holding either transac-
tional or master data and is populated by application programs. The semantic data
maintenance #ALLOWED annotation makes the table editable using the data browser
Transaction SE16.
@EndUserText.label : 'Purchase Document'
@AbapCatalog.enhancementCategory : #EXTENSIBLE_ANY
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #ALLOWED
define table zpurchdocument {
key client : abap.clnt not null;
key purchasedocument : zpurchasedocumentdtel not null;
@EndUserText.label : 'Description'
description : abap.sstring(128);
@EndUserText.label : 'Approval Status'
status : abap.char(1);
@EndUserText.label : 'Priority'
priority : abap.char(1);
@EndUserText.label : 'Purchasing Organization'
purchasingorganization : abap.char(4);
@EndUserText.label : 'Purchase Document Image URL'
128
第 129 页 / 共 465 页
4.1 Core Data Services Views
purchasedocumentimageurl : abap.sstring(255);
include /bobf/s_lib_admin_data;
}
Listing 4.1 Database Table Definition for Purchase Documents
In addition to the actual table fields, we also include a predefined BOPF structure
for admin data (include /bobf/s_lib_admin_data;), which allows us to persist useful
information about who created or changed a table entry and when this took place.
We’ll also include this structure in the purchase document items table.
The database table definition for purchase document items is shown in Listing 4.2. In
contrast to the purchase documents table, it has a compound primary key consist-
ing of the purchasedocumentitem ID and the purchasedocument ID. The purchase docu-
ment items and the purchase documents tables are connected via a foreign key
relationship on the purchasedocument ID field. The table contains fields for the price
of an item and the quantity to purchase as well as fields for the corresponding cur-
rency and unit of measure. Those fields are connected using semantic annotations:
@Semantics.amount.currencyCode for monetary values, and @Semantics.quantity.unit-
OfMeasure for quantities.
@EndUserText.label : 'Purchase Document Item'
…
define table zpurchdocitem {
key client : abap.clnt not null;
@EndUserText.label : 'Purchase Document Item'
key purchasedocumentitem : abap.char(10) not null;
@AbapCatalog.foreignKey.keyType : #KEY
@AbapCatalog.foreignKey.screenCheck : true
key purchasedocument : zpurchasedocumentdtel not null
with foreign key [1..*,1] zpurchdocument
where client = zpurchdocitem.client
and purchasedocument = zpurchdocitem.purchasedocument;
@EndUserText.label : 'Description'
description : abap.sstring(128);
@EndUserText.label : 'Price'
@Semantics.amount.currencyCode : 'zpurchdocitem.currency'
price : abap.curr(13,2);
@EndUserText.label : 'Currency'
currency : abap.cuky;
129
第 130 页 / 共 465 页
4 Developing an SAP Fiori Elements List Report and Object Page
@EndUserText.label : 'Quantity'
@Semantics.quantity.unitOfMeasure : 'zpurchdocitem.quantityunit'
quantity : abap.quan(13,2);
@EndUserText.label : 'Unit'
quantityunit : abap.unit(3);
@EndUserText.label : 'Vendor'
vendor : abap.sstring(32);
@EndUserText.label : 'Vendor Type'
vendortype : abap.sstring(32);
@EndUserText.label : 'Purchase Document Item Image URL'
purchasedocumentitemimageurl : abap.sstring(255);
include /bobf/s_lib_admin_data;
}
Listing 4.2 Database Table Definition for Purchase Document Items
Note
You can use the keyboard shortcut (Ctrl)+(Shift)+(A) to quickly open ABAP devel-
opment objects in Eclipse, such as packages, database tables, or CDS views.
4.1.3 Creating Basic Interface Core Data Services Views
In the previous section, we defined the data model and the underlying database
tables of our application to persist purchase documents and their items. In this sub-
section, we’ll put a semantic and reusable basic interface CDS layer on top of the pre-
viously created tables. We’ll adhere to the standard development guidelines of the
SAP S/4HANA VDM based on CDS views.
The basic interface layer is the foundation layer of CDS views directly deployed on
top of the database tables. As already described in Chapter 1, it isn’t supposed to do
any complex calculations or join already large sets of tables and data; instead, it sim-
ply does a projection of the fields provided by the underlying database tables to fos-
ter fine granular reuse of these views.
To create a CDS view using the ABAP development tools in Eclipse, follow these steps:
1. Open the ABAP perspective in the ABAP development tools in Eclipse.
2. In the ABAP project, select the package node in which you want to create the table
via the Project Explorer view.
130
| Note You can use the keyboard shortcut (Ctrl)+(Shift)+(A) to quickly open ABAP devel- |
| opment objects in Eclipse, such as packages, database tables, or CDS views. |
第 131 页 / 共 465 页
4.1 Core Data Services Views
3. Open the context menu by right-clicking on the package, and select New (cid:2) Other
ABAP Repository (cid:2) Core Data Services (cid:2) Data Definition.
4. In the CDS creation wizard that appears, enter a Name and Description. In our case,
we’ll call the purchase documents view Z_I_PurchaseDocument and the purchase
document items view Z_I_PurchaseDocumentItem.
5. Select one of the provided templates to create a skeleton CDS view, for instance,
Define View, which will create a simple projection view skeleton with one single
data source and without any associations or joins.
6. Click the Finish button in the wizard, and the source code editor will open so you
can add fields or associations to the view.
Note
You can use the shortcut (Ctrl)+(Space) inside the field selection part of the CDS
view source code editor to trigger the Eclipse content assist popover to easily select
fields of the underlying database table or CDS view (see Figure 4.8).
Figure 4.8 Triggering the Eclipse Content Assist for CDS Fields Using the Keyboard Shortcut
Listing 4.3 shows the basic interface view for purchase documents. It does a simple
projection on the purchase document table (table zpurchdocument) to expose all
table fields and provide camel case aliases for fields that are relevant to end users.
According to the naming convention of the SAP S/4HANA VDM development
guidelines for interface layer views, we name the views using the following pattern:
Z_I_<CDSViewName>. The Z_ indicates that this is a custom developed view in the cus-
tomer namespace, and the I_ indicates that this is an interface layer view. The view
131
| Note You can use the shortcut (Ctrl)+(Space) inside the field selection part of the CDS view source code editor to trigger the Eclipse content assist popover to easily select |
| fields of the underlying database table or CDS view (see Figure 4.8). |
第 132 页 / 共 465 页
4 Developing an SAP Fiori Elements List Report and Object Page
is also annotated with the @VDM.viewType: #BASIC annotation that assigns the view to
the basic interface view layer of the VDM.
In addition to the persistent database fields, the view also contains several associa-
tions that are propagated to potential consumers of this view at the end of the field
selection list. By convention, associations start with an underscore, for instance, _Pur-
chaseDocumentItem. Usually, most of the (key) fields contained in a view will have
foreign key associations to other views because data is supposed to be stored in a nor-
malized and redundancy-free form. In some cases, we omit this for the sake of sim-
plicity, but, as an example, we’ve added associations to the Priority, Status, and
PurchasingOrganization views. In the purchase document table, only the Priority,
Status, and PurchasingOrganization keys will be stored; however, additional data, like
texts, can be read via the foreign key associations to these views.
Another important annotation is the authorization check @AccessControl.authoriza-
tionCheck: #CHECK, which enables the restricted access to a CDS view using a data con-
trol language (DCL) access control. We’ll discuss access restrictions for CDS views in
detail in Section 4.1.5.
The @ObjectModel.representativeKey annotation defines the field of the primary key
that is most specific for this view, and the @ObjectModel.semanticKey defines the pri-
mary key of this view. For the purchase document basic interface view, this is the Pur-
chaseDocument field in both cases. Fields containing descriptions or text should be
annotated with @Semantics.text: true. The main description field of the entity can be
linked to the entity key with the @ObjectModel.text.element: ['Description'] anno-
tation.
@AbapCatalog.sqlViewName: 'ZIPURCHDOC'
@EndUserText.label: 'Purchase Document'
@AccessControl.authorizationCheck: #CHECK
@VDM.viewType: #BASIC
@ObjectModel.representativeKey: 'PurchaseDocument'
@ObjectModel.semanticKey: ['PurchaseDocument']
define view Z_I_PurchaseDocument
as select from zpurchdocument
association [0..*] to Z_I_PurchaseDocumentItem as _
PurchaseDocumentItem on $projection.PurchaseDocument = _PurchaseDocumen-
tItem.PurchaseDocument
association [0..1] to Z_I_PurchaseDocumentPriority as _
Priority on $projection.Priority = _Priority.Priority
132
第 133 页 / 共 465 页
4.1 Core Data Services Views
association [0..1] to Z_I_PurchaseDocumentStatus as _
Status on $projection.Status = _Status.Status
association [0..1] to Z_I_PurchasingOrganization as _
PurchasingOrganization on $projection.PurchasingOrganization = _PurchasingOr-
ganization.PurchasingOrganization
{
@ObjectModel.text.element: ['Description']
key purchasedocument as PurchaseDocument,
@Semantics.text: true
description as Description,
@ObjectModel.foreignKey.association: '_Status'
status as Status,
@ObjectModel.foreignKey.association: '_Priority'
priority as Priority,
@ObjectModel.foreignKey.association: '_PurchasingOrganization'
purchasingorganization as PurchasingOrganization,
@Semantics.imageUrl: true
purchasedocumentimageurl as PurchaseDocumentImageURL,
// BOPF Admin Data
crea_date_time,
crea_uname,
lchg_date_time,
lchg_uname,
// Associations
_PurchaseDocumentItem,
_Priority,
_Status,
_PurchasingOrganization
}
Listing 4.3 Basic Interface View on Top of the Purchase Documents Table
(zpurchdocument)
The purchase document item basic interface view is shown in Listing 4.4. Its repre-
sentative key is the PurchaseDocumentItem field as this is the most specific part of its
133
第 134 页 / 共 465 页
4 Developing an SAP Fiori Elements List Report and Object Page
primary key and defines this entity. The semantic key consists of the PurchaseDocu-
ment and PurchaseDocumentItem fields and reflects the primary key of the entity. It con-
tains a foreign key association to the purchase document view as well as to reuse
views for the currency (I_Currency) and the unit of measure (I_UnitOfMeasure) pro-
vided by the standard SAP S/4HANA basic interface view layer. As soon as views are
explicitly released by SAP, they can be used in your own developments without the
risk of introducing breaking changes in future releases. The semantic currency and
unit of measure annotations should be known from the table definition. We added
the @DefaultAggregation:#NONE annotation to the Price and Quantity fields because
all amount fields will be handled, by default, as measures and aggregated by SADL
or the Analytical Engine. However, in our case, we explicitly want to suppress this
default behavior.
@AbapCatalog.sqlViewName: 'ZIPURCHDOCITEM'
@EndUserText.label: 'Purchase Document Item'
@AccessControl.authorizationCheck: #NOT_REQUIRED
@VDM.viewType: #BASIC
@ObjectModel.representativeKey: 'PurchaseDocumentItem'
@ObjectModel.semanticKey: ['PurchaseDocumentItem','PurchaseDocument']
define view Z_I_PurchaseDocumentItem
as select from zpurchdocitem
association [1..1] to Z_I_PurchaseDocument as _
PurchaseDocument on $projection.PurchaseDocument = _
PurchaseDocument.PurchaseDocument
association [0..1] to I_UnitOfMeasure as _
QuantityUnitOfMeasure on $projection.QuantityUnit = _
QuantityUnitOfMeasure.UnitOfMeasure
association [0..1] to I_Currency as _
Currency on $projection.Currency = _Currency.Currency
{
@ObjectModel.text.element: ['Description']
key purchasedocumentitem as PurchaseDocumentItem,
@ObjectModel.foreignKey.association: '_PurchaseDocument'
key purchasedocument as PurchaseDocument,
134
第 135 页 / 共 465 页
4.1 Core Data Services Views
@Semantics.text: true
description as Description,
vendor as Vendor,
vendortype as VendorType,
@Semantics.amount.currencyCode: 'Currency'
@DefaultAggregation: #NONE
price as Price,
@Semantics.currencyCode: true
@ObjectModel.foreignKey.association: '_Currency'
currency as Currency,
@Semantics.quantity.unitOfMeasure: 'QuantityUnit'
@DefaultAggregation: #NONE
quantity as Quantity,
@Semantics.unitOfMeasure: true
@ObjectModel.foreignKey.association: '_QuantityUnitOfMeasure'
quantityunit as QuantityUnit,
@Semantics.imageUrl: true
purchasedocumentitemimageurl as PurchaseDocumentItemImageURL,
// BOPF Admin Data
crea_date_time,
crea_uname,
lchg_date_time,
lchg_uname,
// Associations
_PurchaseDocument,
_QuantityUnitOfMeasure,
_Currency
}
Listing 4.4 Basic Interface View on Top of the Purchase Document Items Table
(zpurchdocitem)
135
第 136 页 / 共 465 页
4 Developing an SAP Fiori Elements List Report and Object Page
4.1.4 Adding Calculated Fields
With the CDS DDL, it’s possible to dynamically calculate fields based on other per-
sistent fields already present in the database. In the past, such calculated values
might have been calculated on the application server or, in the worst case, were pre-
calculated and stored in redundant aggregate tables. However, with the launch of SAP
HANA, this has become obsolete as we can easily aggregate and calculate values on
the fly now, which potentially reduces the data footprint of the system and improves
the performance by pushing data-intensive calculations and aggregations to the
database layer. In the following, we’ll calculate several values that are of interest for
our application but don’t have to be stored on the database as they would introduce
redundancy and can be calculated dynamically using CDS views at runtime.
Calculating the Overall Item Price
One very simple example of a calculated value is the overall price of a purchase doc-
ument item. We’ve persisted the price of a single item and the requested quantity on
the database but not the overall price. To calculate the overall price, we can simply
multiply the requested quantity by the price of a single item and provide a new name
for the field using an alias. For example, with an item price of 50 and a quantity of 10,
the overall price of this item would be 50 ∙ 10 = 500. How this can be implemented in
the Z_I_PurchaseDoumentItem basic view is shown in the following listing. Though this
is a calculated field, we can also reference the already-persisted currency field.
…
@Semantics.amount.currencyCode: 'Currency'
@DefaultAggregation: #NONE
quantity * price as OverallItemPrice,
…
Calculating Overall Purchase Document Price by Introducing a Composite
Interface View and Using Test-Driven Development
Additionally, we’re also interested in the overall price of a purchase document. To cal-
culate the overall price, we’ll make use of the previously calculated overall item price
as the overall price of a purchase document can be calculated by summing up all
overall item prices of its assigned items. To do this, we must put an additional view
on top of the basic purchase document view, which we’ll name Z_I_PurchDocOver-
allPrice and assign to the composite interface layer of the VDM as it will contain a
136