RAP End-to-End Tutorial: Vom Datenmodell zur Fiori App

kategorie
RAP
Veröffentlicht
autor
Johannes

Dieses End-to-End Tutorial fuehrt Sie durch den kompletten Entwicklungsprozess einer RAP-Anwendung - von der leeren Datenbanktabelle bis zur fertigen Fiori Elements App. Sie erstellen eine Projektverwaltung mit vollstaendiger CRUD-Funktionalitaet.

Zielsetzung

Am Ende dieses Tutorials haben Sie:

  • Eine Datenbanktabelle fuer Projektdaten
  • Interface und Projection CDS Views
  • Behavior Definition mit CRUD und Custom Actions
  • OData V4 Service fuer die API
  • Funktionierende Fiori Elements UI

Voraussetzungen

  • SAP BTP ABAP Environment oder S/4HANA 2022+
  • ABAP Development Tools (ADT) fuer Eclipse
  • Grundkenntnisse in ABAP (SQL, Datentypen)

Fuer den Einstieg in die Entwicklungsumgebung siehe ABAP Cloud Entwicklungsumgebung einrichten.

Architekturueberblick

┌─────────────────────────────────────────────────────────┐
│ SAP Fiori Elements UI │
│ (automatisch aus Annotations generiert) │
├─────────────────────────────────────────────────────────┤
│ OData V4 Service │
│ Service Binding (SRVB): ZUI_PROJECT_O4 │
├─────────────────────────────────────────────────────────┤
│ Service Definition (SRVD) │
│ ZUI_PROJECT_O4 │
├─────────────────────────────────────────────────────────┤
│ Projection Layer (C_*) │
│ CDS View: ZC_PROJECT Behavior: projection │
│ + Metadata Extension (UI Annotations) │
├─────────────────────────────────────────────────────────┤
│ Business Object Layer (I_*) │
│ CDS View: ZI_PROJECT Behavior Definition (BDEF) │
│ Behavior Implementation (BIL) │
├─────────────────────────────────────────────────────────┤
│ Datenbanktabelle: ZPROJECT │
└─────────────────────────────────────────────────────────┘

Schritt 1: Datenbanktabelle erstellen

Die Datenbanktabelle bildet die Persistenzschicht unseres Business Objects.

ADT Workflow

  1. Rechtsklick auf Ihr Package → NewOther ABAP Repository Object
  2. Suche: Database Table → Next
  3. Name: ZPROJECT | Description: Project Master Data
  4. Finish

Tabellendefinition

@EndUserText.label : 'Project Master Data'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zproject {
key client : abap.clnt not null;
key project_id : abap.char(10) not null;
project_name : abap.char(100);
description : abap.string(1024);
responsible_person : abap.char(40);
start_date : abap.dats;
end_date : abap.dats;
@Semantics.amount.currencyCode : 'zproject.currency_code'
budget : abap.curr(15,2);
currency_code : abap.cuky;
status : abap.char(1);
priority : abap.char(1);
@Semantics.user.createdBy : true
created_by : abap.char(12);
@Semantics.systemDateTime.createdAt : true
created_at : timestampl;
@Semantics.user.lastChangedBy : true
last_changed_by : abap.char(12);
@Semantics.systemDateTime.lastChangedAt : true
last_changed_at : timestampl;
}

Aktivieren: Ctrl+F3

Die @Semantics-Annotationen ermöglichen automatisches Befuellen von Audit-Feldern durch das RAP Framework.


Schritt 2: Interface CDS View (I_*)

Die Interface View definiert das semantische Datenmodell des Business Objects. Sie ist die stabile API fuer andere Konsumenten.

ADT Workflow

  1. Rechtsklick auf Package → NewOther ABAP Repository Object
  2. Suche: Data Definition → Next
  3. Name: ZI_PROJECT | Description: Project - Interface View
  4. Template: Define Root View Entity
  5. Finish

CDS View Definition

@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Project - Interface View'
define root view entity ZI_PROJECT
as select from zproject
{
key project_id as ProjectId,
project_name as ProjectName,
description as Description,
responsible_person as ResponsiblePerson,
start_date as StartDate,
end_date as EndDate,
@Semantics.amount.currencyCode: 'CurrencyCode'
budget as Budget,
@Semantics.currencyCode: true
currency_code as CurrencyCode,
status as Status,
priority as Priority,
@Semantics.user.createdBy: true
created_by as CreatedBy,
@Semantics.systemDateTime.createdAt: true
created_at as CreatedAt,
@Semantics.user.lastChangedBy: true
last_changed_by as LastChangedBy,
@Semantics.systemDateTime.lastChangedAt: true
last_changed_at as LastChangedAt
}

Wichtig: Das Keyword root kennzeichnet die Wurzel-Entity des Business Objects. Mehr zu CDS Views unter ABAP CDS Views.


Schritt 3: Behavior Definition (BDEF)

Die Behavior Definition deklariert, was mit dem Business Object gemacht werden kann (CRUD, Actions, Validations, Determinations).

ADT Workflow

  1. Rechtsklick auf ZI_PROJECTNew Behavior Definition
  2. Implementation Type: Managed
  3. Finish

BDEF Code

managed implementation in class zbp_i_project unique;
strict ( 2 );
define behavior for ZI_PROJECT alias Project
persistent table zproject
lock master
authorization master ( instance )
etag master LastChangedAt
{
// Standard CRUD Operationen
create;
update;
delete;
// Feldsteuerung
field ( readonly ) ProjectId;
field ( readonly ) CreatedBy, CreatedAt, LastChangedBy, LastChangedAt;
field ( numbering : managed ) ProjectId;
// Validierungen
validation validateDates on save { field StartDate, EndDate; }
validation validateBudget on save { field Budget; }
// Determinations (automatische Werte)
determination setDefaultStatus on modify { create; }
// Custom Actions
action ( features : instance ) completeProject result [1] $self;
action ( features : instance ) cancelProject result [1] $self;
// Feldmapping zur Datenbanktabelle
mapping for zproject
{
ProjectId = project_id;
ProjectName = project_name;
Description = description;
ResponsiblePerson = responsible_person;
StartDate = start_date;
EndDate = end_date;
Budget = budget;
CurrencyCode = currency_code;
Status = status;
Priority = priority;
CreatedBy = created_by;
CreatedAt = created_at;
LastChangedBy = last_changed_by;
LastChangedAt = last_changed_at;
}
}

Erklaerung der Schluesselwoerter:

  • managed: RAP Framework uebernimmt CRUD automatisch
  • strict ( 2 ): Aktiviert Best-Practice-Pruefungen
  • numbering : managed: Automatische ID-Vergabe
  • etag master: Optimistic Locking fuer Parallelzugriff

Fuer Details zu Managed vs. Unmanaged siehe RAP Managed vs Unmanaged.


Schritt 4: Behavior Implementation (BIL)

Die Behavior Implementation enthaelt die ABAP-Logik fuer Validations, Determinations und Actions.

Automatisch generierte Klasse

Nach Aktivierung der BDEF generiert ADT die Klasse ZBP_I_PROJECT. Oeffnen Sie diese und implementieren Sie die Local Handler Class:

CLASS lhc_project DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS:
get_instance_features FOR INSTANCE FEATURES
IMPORTING keys REQUEST requested_features FOR Project RESULT result,
validateDates FOR VALIDATE ON SAVE
IMPORTING keys FOR Project~validateDates,
validateBudget FOR VALIDATE ON SAVE
IMPORTING keys FOR Project~validateBudget,
setDefaultStatus FOR DETERMINE ON MODIFY
IMPORTING keys FOR Project~setDefaultStatus,
completeProject FOR MODIFY
IMPORTING keys FOR ACTION Project~completeProject RESULT result,
cancelProject FOR MODIFY
IMPORTING keys FOR ACTION Project~cancelProject RESULT result.
ENDCLASS.
CLASS lhc_project IMPLEMENTATION.
METHOD get_instance_features.
READ ENTITIES OF zi_project IN LOCAL MODE
ENTITY Project
FIELDS ( Status )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_project)
FAILED failed.
result = VALUE #( FOR ls_project IN lt_project
( %tky = ls_project-%tky
%features-%action-completeProject = COND #(
WHEN ls_project-Status = 'A' THEN if_abap_behv=>fc-o-enabled
ELSE if_abap_behv=>fc-o-disabled )
%features-%action-cancelProject = COND #(
WHEN ls_project-Status = 'A' OR ls_project-Status = 'N'
THEN if_abap_behv=>fc-o-enabled
ELSE if_abap_behv=>fc-o-disabled )
) ).
ENDMETHOD.
METHOD validateDates.
READ ENTITIES OF zi_project IN LOCAL MODE
ENTITY Project
FIELDS ( StartDate EndDate )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_project).
LOOP AT lt_project INTO DATA(ls_project).
IF ls_project-EndDate IS NOT INITIAL
AND ls_project-EndDate < ls_project-StartDate.
APPEND VALUE #(
%tky = ls_project-%tky
%element-EndDate = if_abap_behv=>mk-on
) TO failed-project.
APPEND VALUE #(
%tky = ls_project-%tky
%element-EndDate = if_abap_behv=>mk-on
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'Enddatum muss nach Startdatum liegen' )
) TO reported-project.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD validateBudget.
READ ENTITIES OF zi_project IN LOCAL MODE
ENTITY Project
FIELDS ( Budget )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_project).
LOOP AT lt_project INTO DATA(ls_project).
IF ls_project-Budget < 0.
APPEND VALUE #(
%tky = ls_project-%tky
%element-Budget = if_abap_behv=>mk-on
) TO failed-project.
APPEND VALUE #(
%tky = ls_project-%tky
%element-Budget = if_abap_behv=>mk-on
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'Budget darf nicht negativ sein' )
) TO reported-project.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD setDefaultStatus.
READ ENTITIES OF zi_project IN LOCAL MODE
ENTITY Project
FIELDS ( Status )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_project).
MODIFY ENTITIES OF zi_project IN LOCAL MODE
ENTITY Project
UPDATE FIELDS ( Status Priority )
WITH VALUE #( FOR ls_project IN lt_project
WHERE ( Status IS INITIAL )
( %tky = ls_project-%tky
Status = 'N'
Priority = 'M' ) )
REPORTED DATA(reported_modify).
ENDMETHOD.
METHOD completeProject.
MODIFY ENTITIES OF zi_project IN LOCAL MODE
ENTITY Project
UPDATE FIELDS ( Status )
WITH VALUE #( FOR key IN keys
( %tky = key-%tky
Status = 'C' ) )
FAILED failed
REPORTED reported.
READ ENTITIES OF zi_project IN LOCAL MODE
ENTITY Project
ALL FIELDS
WITH CORRESPONDING #( keys )
RESULT result.
ENDMETHOD.
METHOD cancelProject.
MODIFY ENTITIES OF zi_project IN LOCAL MODE
ENTITY Project
UPDATE FIELDS ( Status )
WITH VALUE #( FOR key IN keys
( %tky = key-%tky
Status = 'X' ) )
FAILED failed
REPORTED reported.
READ ENTITIES OF zi_project IN LOCAL MODE
ENTITY Project
ALL FIELDS
WITH CORRESPONDING #( keys )
RESULT result.
ENDMETHOD.
ENDCLASS.

Status-Werte: N = Neu, A = Aktiv, C = Abgeschlossen, X = Abgebrochen

Fuer mehr Details zu Validations und Determinations siehe RAP Determinations und Validations.


Schritt 5: Projection CDS View (C_*)

Die Projection View ist die UI-spezifische Sicht auf das Business Object. Sie definiert, welche Felder fuer eine bestimmte App sichtbar sind.

ADT Workflow

  1. Rechtsklick auf Package → NewData Definition
  2. Name: ZC_PROJECT | Description: Project - Projection View
  3. Template: Define Projection View
  4. Finish

Projection View Code

@EndUserText.label: 'Project - Projection View'
@AccessControl.authorizationCheck: #NOT_REQUIRED
@Metadata.allowExtensions: true
@Search.searchable: true
define root view entity ZC_PROJECT
provider contract transactional_query
as projection on ZI_PROJECT
{
key ProjectId,
@Search.defaultSearchElement: true
@Search.fuzzinessThreshold: 0.8
ProjectName,
Description,
@Search.defaultSearchElement: true
ResponsiblePerson,
StartDate,
EndDate,
@Semantics.amount.currencyCode: 'CurrencyCode'
Budget,
@Semantics.currencyCode: true
CurrencyCode,
@ObjectModel.text.element: ['StatusText']
Status,
case Status
when 'N' then 'Neu'
when 'A' then 'Aktiv'
when 'C' then 'Abgeschlossen'
when 'X' then 'Abgebrochen'
else 'Unbekannt'
end as StatusText : localized,
@ObjectModel.text.element: ['PriorityText']
Priority,
case Priority
when 'H' then 'Hoch'
when 'M' then 'Mittel'
when 'L' then 'Niedrig'
else 'Unbekannt'
end as PriorityText : localized,
CreatedBy,
CreatedAt,
LastChangedBy,
LastChangedAt
}

Hinweis: provider contract transactional_query aktiviert die RAP-Transaktionsunterstuetzung. Die case-Ausdruecke erzeugen lesbare Texte fuer Status und Prioritaet.


Schritt 6: Projection Behavior Definition

Die Projection BDEF bestimmt, welche Operationen auf der Projection-Ebene verfuegbar sind.

ADT Workflow

  1. Rechtsklick auf ZC_PROJECTNew Behavior Definition
  2. Implementation Type: Projection
  3. Finish

Projection BDEF Code

projection;
strict ( 2 );
define behavior for ZC_PROJECT alias Project
{
use create;
use update;
use delete;
use action completeProject;
use action cancelProject;
}

Das use Keyword delegiert die Operationen an die Interface-Ebene.


Schritt 7: Metadata Extension (UI Annotations)

Die Metadata Extension definiert das UI-Layout der Fiori Elements App.

ADT Workflow

  1. Rechtsklick auf ZC_PROJECTNew Metadata Extension
  2. Name: ZC_PROJECT
  3. Finish

Metadata Extension Code

@Metadata.layer: #CORE
annotate entity ZC_PROJECT with
{
@UI.headerInfo: {
typeName: 'Projekt',
typeNamePlural: 'Projekte',
title: { value: 'ProjectName' },
description: { value: 'ProjectId' }
}
@UI.facet: [
{ id: 'GeneralInfo',
purpose: #STANDARD,
type: #IDENTIFICATION_REFERENCE,
label: 'Allgemeine Informationen',
position: 10 },
{ id: 'Dates',
purpose: #STANDARD,
type: #FIELDGROUP_REFERENCE,
targetQualifier: 'Dates',
label: 'Zeitraum',
position: 20 },
{ id: 'Financial',
purpose: #STANDARD,
type: #FIELDGROUP_REFERENCE,
targetQualifier: 'Financial',
label: 'Budget',
position: 30 }
]
@UI: { lineItem: [{ position: 10, importance: #HIGH }],
identification: [{ position: 10 }],
selectionField: [{ position: 10 }] }
ProjectId;
@UI: { lineItem: [{ position: 20, importance: #HIGH }],
identification: [{ position: 20 }],
selectionField: [{ position: 20 }] }
ProjectName;
@UI: { identification: [{ position: 30 }] }
Description;
@UI: { lineItem: [{ position: 30 }],
identification: [{ position: 40 }],
selectionField: [{ position: 30 }] }
ResponsiblePerson;
@UI: { lineItem: [{ position: 40 }],
fieldGroup: [{ qualifier: 'Dates', position: 10 }] }
StartDate;
@UI: { lineItem: [{ position: 50 }],
fieldGroup: [{ qualifier: 'Dates', position: 20 }] }
EndDate;
@UI: { lineItem: [{ position: 60 }],
fieldGroup: [{ qualifier: 'Financial', position: 10 }] }
Budget;
@UI.hidden: true
CurrencyCode;
@UI: { lineItem: [{ position: 70, importance: #HIGH,
criticality: 'StatusCriticality' }],
identification: [{ position: 50 }],
selectionField: [{ position: 40 }] }
@UI.textArrangement: #TEXT_ONLY
Status;
@UI: { lineItem: [{ position: 80 }],
identification: [{ position: 60 }] }
@UI.textArrangement: #TEXT_ONLY
Priority;
@UI: { lineItem: [{ position: 100, type: #FOR_ACTION, dataAction: 'completeProject',
label: 'Abschliessen' }] }
@UI: { identification: [{ position: 100, type: #FOR_ACTION,
dataAction: 'completeProject', label: 'Projekt abschliessen' }] }
@UI: { lineItem: [{ position: 110, type: #FOR_ACTION, dataAction: 'cancelProject',
label: 'Abbrechen' }] }
@UI: { identification: [{ position: 110, type: #FOR_ACTION,
dataAction: 'cancelProject', label: 'Projekt abbrechen' }] }
}

Mehr zu UI Annotations unter CDS Annotations.


Schritt 8: Service Definition (SRVD)

Die Service Definition bestimmt, welche Entities ueber den OData Service exponiert werden.

ADT Workflow

  1. Rechtsklick auf Package → NewOther ABAP Repository Object
  2. Suche: Service Definition → Next
  3. Name: ZUI_PROJECT_O4
  4. Finish

Service Definition Code

@EndUserText.label: 'Project Service Definition'
define service ZUI_PROJECT_O4 {
expose ZC_PROJECT as Project;
}

Schritt 9: Service Binding (SRVB)

Das Service Binding erstellt den eigentlichen OData Endpoint.

ADT Workflow

  1. Rechtsklick auf Package → NewOther ABAP Repository Object
  2. Suche: Service Binding → Next
  3. Name: ZUI_PROJECT_O4
  4. Binding Type: OData V4 - UI
  5. Service Definition: ZUI_PROJECT_O4
  6. Finish

Aktivierung und Publish

  1. Aktivieren: Ctrl+F3
  2. Im Service Binding Editor: Publish klicken
  3. Nach erfolgreichem Publish: Entity Project markieren → Preview klicken

Der Browser oeffnet die Fiori Elements Anwendung.


Haeufige Fehler und Loesungen

Fehler: “No behavior implementation found”

Ursache: Die Behavior Implementation Klasse existiert nicht oder ist nicht aktiviert.

Loesung:

  1. Oeffnen Sie die BDEF
  2. Rechtsklick → NavigateBehavior Implementation
  3. Aktivieren Sie die Klasse mit Ctrl+F3

Fehler: “Field X is not mapped”

Ursache: Ein CDS-Feld hat kein entsprechendes Mapping zur Datenbanktabelle.

Loesung: Ergaenzen Sie das Mapping in der BDEF:

mapping for zproject
{
MissingField = missing_field;
}

Fehler: “Authorization check failed”

Ursache: @AccessControl.authorizationCheck: #CHECK ist gesetzt, aber keine Access Control existiert.

Loesung: Aendern Sie die Annotation zu #NOT_REQUIRED oder erstellen Sie eine Access Control (DCL).

Fehler: “Draft table not found”

Ursache: Draft ist in der BDEF aktiviert (with draft;), aber die Draft-Tabelle existiert nicht.

Loesung: Erstellen Sie die Draft-Tabelle oder entfernen Sie with draft; aus der BDEF.

Weitere Loesungen unter ABAP Cloud Fehler und Loesungen.


Naechste Schritte

Mit diesem Grundgeruest koennen Sie die Anwendung erweitern:

  • Draft-Funktionalitaet: Zwischenspeichern von Eingaben - siehe RAP Draft Handling
  • Value Helps: Dropdown-Listen fuer Status und Prioritaet - siehe RAP Value Helps
  • Berechtigungen: Instanzbasierte Autorisierung - siehe RAP Authorization
  • Feature Control: Dynamische Feld-/Button-Verfuegbarkeit - siehe RAP Feature Control
  • Assoziationen: Untergeordnete Entities (z.B. Projektaufgaben) - siehe RAP Basics

Fuer ein interaktives Einsteiger-Tutorial mit Schritt-fuer-Schritt-Screenshots siehe RAP Tutorial Teil 1: Deine erste Fiori App.


Zusammenfassung

Dieses Tutorial hat den vollstaendigen RAP-Entwicklungszyklus durchlaufen:

SchichtArtefaktZweck
PersistenzZPROJECT (Table)Datenspeicherung
DatenmodellZI_PROJECT (CDS)Semantisches Modell, Business API
VerhaltenBDEF + BILCRUD, Validations, Actions
ProjectionZC_PROJECT (CDS)UI-spezifische Sicht
UIMetadata ExtensionFiori Layout Annotations
ServiceSRVD + SRVBOData Endpoint

Mit dem RAP Managed Szenario uebernimmt das Framework die komplette CRUD-Logik. Sie konzentrieren sich auf die Geschaeftslogik in Validations, Determinations und Actions. Fuer komplexere Anforderungen mit Legacy-Integration siehe RAP Managed vs Unmanaged.