
RAP - Generierung mit Template
Die Generatoren in RAP sind mächtig, wenn es um die schnelle Bereitstellung von RAP Objekten geht. Über Templates kannst du die Entitäten noch einmal schneller anlegen, wenn du eine Schulung machst.
Inhaltsverzeichnis
In diesem Artikel generieren wir uns im ersten Schritt die Templates und erzeugen uns daraus ein neues RAP Objekt, welches als Grundlage für folgenden Artikel wird.
Einleitung
Über die verschiedenen RAP Generatoren haben wir bereits in unterschiedlichen Artikeln berichtet. Egal ob der klassische Generator, die Fiori App, die Business Configuration oder der neue Generator from Scratch, alle generieren am Ende ein RAP Objekt. Hast du dich ausreichend mit RAP und der Entwicklung beschäftigt, würden wir dir immer die Generatoren empfehlen, einfach um Zeit zu sparen und wiederholende Arbeiten zu reduzieren.
Datenmodell
Dabei erstellen wir eine Anwendung mit einem neuen Datenmodell, um einige Use-Cases und Implementierungen durchführen zu können. Dabei erstellen wir eine Umsatz App die eng verknüpft ist mit unserem CDS Datenmodell, welches wir auch bereits schon für andere Apps verwendet haben. Auf oberster Ebene gibt es einen Umsatz pro Partner den wir pflegen können. Dort werden auch Abweichungen eingetragen in Form von einer Währung oder einem Prozentsatz. Darunter haben wir eine Entität für Material, dass beim Verkauf beteiligt war, die eigentlichen Verkäufer mit ihrem Anteil und eine Information, die mehrsprachig gepflegt wird.
Die Beziehungen Partner und Material stammen aus dem CDS Modell, der Business User und die Sprache aus dem Standard im System. Hier beziehen wir bestimmte Daten aus dem System.
Generierung
In diesem Kapitel kümmern wir uns um die Generierung der Artefakte.
Generator
Im letzten Artikel hatten wir zusammen einen Generator für DDIC Artefakte gebaut, um uns automatisiert Objekte im System anlegen zu lassen. Da wir für das Datenmodell einige Entitäten, Datenelemente und Domänen benötigen, soll der Generator die Arbeit für uns übernehmen. Grundsätzlich kannst du auch fertige Teile des Datenmodells aus dem GitHub Repository ziehen (siehe unten).
Konfiguration
Für die Konfiguration legen wir eine ausführbare Klasse im neuen Paket ZBS_DEMO_RAP_SALES an. Die vollständige Konfiguration findest du in GitHub in der Klasse ZCL_SB_DEMO_RAP_SALES_FIELDS. Dabei verwenden wir die ausführbare Klasse mit XCO Template, da diese am besten mit den XCO Klassen für die Ausgabe zusammenarbeitet. Insgesamt wollen wir vier abstrakte Entitäten anlegen, um diese später als Template zu verwenden:
- ZBS_S_SASale
- ZBS_S_SAInfo
- ZBS_S_SASold
- ZBS_S_SASeller
Anlage
Führen wir nun die Konfiguration aus, dann werden im System die verschiedenen Datenelement und Domänen generiert. Kommt es bei dir zu einem Fehler wegen des Pakets oder des fehlenden Transports, dann kannst du die Informationen noch in der Konfiguration nachtragen.
RAP Generator
Führen wir nun im nächsten Schritt den RAP Generator im System aus und verwenden die angelegten Templates für die Generierung unsere RAP BOs.
Konfiguration
Wie bereits im passenden Artikel oben beschrieben, starten wir den Generator direkt auf dem Paket. Der Generator from Scratch ist On-Prem erst mit der Version 2025 verfügbar, wir arbeiten aktuell vor allem auf dem ABAP Environment.
Dort wählst du den Generator "OData UI Service from Scratch" den wir für die Templates verwenden wollen. Im nächsten Schritt ist bereits dass Paket vorbelegt, daher können wir den Schritt einfach bestätigen und landen bei der Generierung des Objekts. Dann können wir direkt auf den Punkt "Business Object Entities" springen, um unser RAP BO zu definieren. Hier wenden wir die abstrakten Entitäten um die Templates zu befüllen.
Das kann einen kurzen Moment dauern, da die Struktur analysiert wird und die Felder direkt alle angelegt werden. Mit den Templates sparen wir uns damit die manuelle Anlage aller Felder, Texte und Beziehungen untereinander. Wurden nun die 4 Knoten definiert, dann können wir zum Punkt "Service Configuration" springen. Wieso eigentlich erst jetzt? Die ROOT Entität überschreibt uns das Feld "ProjectName", welches wir erst am Ende definieren wollen. Hier definieren wir ein Präfix für die Generierung.
Generierung
Im nächsten Schritt erhalten wir dann die Liste der Objekte, die generiert werden. Nach einer kurzen Prüfung der vergebenen Namen, können wir dann den Generator starten, der dann einiges an Zeit für die Objekte benötigt.
Ist die Generierung der Objekte abgeschlossen erhalten wir eine Info vom System und können zum Service navigieren. Dort aktivieren wir den OData Service und können dann die Fiori Elements Preview anschauen.
Analyse
In unseren Templates hatten wir keine Schlüssel definiert. Aktuell generiert der RAP Generator automatisch Schlüssel vom Typ UUID für alle Entitäten und definiert auf dieser Basis auch die Beziehungen der Objekte untereinander. Wenn du Informationen Felder anlegst, solltest du diese Eigenschaft berücksichtigen. Schauen wir uns einmal die Haupttabelle für die Sales an, dann finden wir die UUID als Schlüssel unsere Felder mit den passenden Datenelementen, die Beziehungen der Daten untereinander.
@EndUserText.label : 'Database Table for ZBS_SASALE'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zbs_sasale {
key client : abap.clnt not null;
key uuid : sysuuid_x16 not null;
partnernumber : zbs_demo_sa_partner;
salesdate : zbs_demo_sa_date;
@Semantics.amount.currencyCode : 'zbs_sasale.salescurrency'
salesvolume : zbs_demo_sa_amount;
salescurrency : zbs_demo_sa_currency;
@Semantics.amount.currencyCode : 'zbs_sasale.differencecurrency'
differenceamount : zbs_demo_sa_amount;
differencecurrency : zbs_demo_sa_currency;
@Semantics.quantity.unitOfMeasure : 'zbs_sasale.differenceunit'
differencequantity : zbs_demo_sa_quantity;
differenceunit : zbs_demo_sa_unit;
salecomment : zbs_demo_sa_comment;
local_created_by : abp_creation_user;
local_created_at : abp_creation_tstmpl;
local_last_changed_by : abp_locinst_lastchange_user;
local_last_changed_at : abp_locinst_lastchange_tstmpl;
last_changed_at : abp_lastchange_tstmpl;
}
Schauen wir uns Core Data Service auf dieser Basis an, dann fallen einige nicht so schöne Dinge auf. Aktuell verwendet der Generator noch die alten Kardinalitäten für die Compositions, hier sollten mittlerweile die sprechenden Namen verwendet werden. Ebenso hat der Generator unsere Feldnamen auf PascalName-Basis ignoriert, wodurch das Datenmodell jetzt nicht ganz so "hübsch" ist.
@AccessControl.authorizationCheck: #MANDATORY
@Metadata.allowExtensions: true
@ObjectModel.sapObjectNodeType.name: 'ZBS_GlobalSale'
@EndUserText.label: '###GENERATED Core Data Service Entity'
define root view entity ZBS_R_SASALE
as select from zbs_sasale as SASale
composition [1..*] of ZBS_R_SAINFO as _SAInfo
composition [1..*] of ZBS_R_SASOLD as _SASold
composition [1..*] of ZBS_R_SASELLER as _SASeller
{
key uuid as UUID,
partnernumber as Partnernumber,
salesdate as Salesdate,
@Semantics.amount.currencyCode: 'Salescurrency'
salesvolume as Salesvolume,
salescurrency as Salescurrency,
@Semantics.amount.currencyCode: 'Differencecurrency'
differenceamount as Differenceamount,
differencecurrency as Differencecurrency,
@Semantics.quantity.unitOfMeasure: 'Differenceunit'
differencequantity as Differencequantity,
differenceunit as Differenceunit,
salecomment as Salecomment,
@Semantics.user.createdBy: true
local_created_by as LocalCreatedBy,
@Semantics.systemDateTime.createdAt: true
local_created_at as LocalCreatedAt,
@Semantics.user.localInstanceLastChangedBy: true
local_last_changed_by as LocalLastChangedBy,
@Semantics.systemDateTime.localInstanceLastChangedAt: true
local_last_changed_at as LocalLastChangedAt,
@Semantics.systemDateTime.lastChangedAt: true
last_changed_at as LastChangedAt,
_SAInfo,
_SASold,
_SASeller
}
Sprache
Aktuell scheint es ein Problem mit Felder vom Typ SPRAS zu geben. Das Feld wurde bei der Generierung aus der Entität geschmissen und wurde daher nicht beachtet. Daher müssen wir im Nachgang das Feld noch mit in die verschiedenen Objekte aufnehmen.
- Tabelle - ZBS_SAINFO
- Core Data Service - ZBS_R_SAInfo, ZBS_C_SAInfo
- Behavior Definition - ZBS_R_SASale
- Nachgenerierung der Draft Tabelle
Hinweis: Nach der Generierung der Artefakte sollte kein Fehler mehr im Service sein. Um die UI-Annotationen würden wir uns beim nächsten Mal kümmern.
Refactoring
Wenn dich die Unschärfen nicht stören (PascalCase der Feldnamen), dann kannst du mit diesem Stand später weiterarbeiten. Wir würden nun das Datenmodell noch einmal säubern und auf einen aktuellen Stand bringen. Die aktuelle Version findest du am Ende in GitHub und kannst das saubere Modell laden oder das Refactoring selbst durchführen. Dabei solltest du dir die Entitäten (Core Data Service), Behavior Definition und Metadata Extensions anschauen. Hier einmal der Auszug nach dem Refactoring, die Kardinalität wurde überarbeitet und PascalCase in den Namen wiederhergestellt.
define root view entity ZBS_R_SASALE
as select from zbs_sasale as SASale
composition of exact one to many ZBS_R_SAINFO as _SAInfo
composition of exact one to many ZBS_R_SASOLD as _SASold
composition of exact one to many ZBS_R_SASELLER as _SASeller
{
key uuid as UUID,
partnernumber as PartnerNumber,
salesdate as SalesDate,
@Semantics.amount.currencyCode: 'Salescurrency'
salesvolume as SalesVolume,
salescurrency as SalesCurrency,
}
Daten
Nachdem das Objekt angelegt und generiert wurde, legen wir noch einige Daten an. Dazu definieren wir uns eine Klasse ZCL_BS_DEMO_RAP_SALES_DATA die du bei dir im System ausführen musst, damit die Entitäten mit Daten versorgt werden.
Bereinigung
Im ersten Schritt würden wir alle Tabellen bereinigen, damit wir die Datengenerierung mehrfach ausführen können. Dabei solltest du neben den eigentlichen Tabellen auch den Draft bereinigen, da hier ebenfalls alte Bestandteile liegen können, die du nicht gespeichert hast.
DELETE FROM zbs_sasale.
DELETE FROM zbs_sasale_d.
DELETE FROM zbs_sainfo.
DELETE FROM zbs_sainfo_d.
DELETE FROM zbs_saseller.
DELETE FROM zbs_saseller_d.
DELETE FROM zbs_sasold.
DELETE FROM zbs_sasold_d.
COMMIT WORK.
Befüllung
Für die Befüllung legen wir uns verschiedene Tabellen an, um die abhängigen Informationen mit einem Aufruf in die Datenbank zu bringen. Da wir in diesem Fall immer über die Root Entität gehen und die unteren Daten per Assoziation einfügen, definieren wir auch unsere Tabellen über diesen Weg.
DATA sales TYPE TABLE FOR CREATE zbs_r_sasale.
DATA infos TYPE TABLE FOR CREATE zbs_r_sasale\_SAInfo.
DATA sellers TYPE TABLE FOR CREATE zbs_r_sasale\_SASeller.
DATA solds TYPE TABLE FOR CREATE zbs_r_sasale\_SASold.
Anlage
Die Befüllung der Tabellen findest du im GitHub Repository und die einzelnen Datensätze würden wir hier nicht noch einmal im Detail beschreiben. Zum Abschluss rufen wir über EML die Erzeugung der Instanzen und Tabelleneinträge auf. Auf der Ebene von ROOT haben wir die CID selbst definiert, da wir diese für die Unterentitäten benötigen. Dort übergeben wir über CID_REF die Referenz, um die Datensätze dem Root Eintrag zuzuordnen und stellen die Entitäten selbst auf AUTO FILL CID, womit sich das Framework um die Befüllung der CID im Datensatz kümmert. Um die Datendefinition einfach zu halten, verwenden wir WITH für die Felder. Weitere Details zu den EML Varianten findest du im Artikel.
MODIFY ENTITIES OF zbs_r_sasale
ENTITY SASale
CREATE FIELDS ( PartnerNumber SalesDate SalesVolume SalesCurrency SaleComment DifferenceAmount DifferenceCurrency )
WITH sales
ENTITY SASale
CREATE BY \_SAInfo AUTO FILL CID FIELDS ( Language TextInformation )
WITH infos
ENTITY SASale
CREATE BY \_SASeller AUTO FILL CID FIELDS ( SellerId Quota Confirmed )
WITH sellers
ENTITY SASale
CREATE BY \_SASold AUTO FILL CID FIELDS ( MaterialId )
WITH solds
FAILED DATA(failed)
MAPPED DATA(mapped)
REPORTED DATA(reported).
Test
Nachdem wir nun auch Testdaten angelegt haben, schauen wir uns die Anwendung einmal im Detail an. Nach dem Aufruf und dem Laden der ersten Einträge, erhalten wir viele Felder und Filter im List Report.
Navigieren wir in die Details, dann sehen wir noch sehr viele UUIDS und noch keine richtige Struktur in den Details. Auf dem Bild siehst du einen Ausschnitt aus dem Bild, die weiteren Tabellen im unteren Bereich haben wir erst einmal weggelassen.
Vollständiges Beispiel
Das vollständige Coding findest du wie immer im GitHub Repository für unsere RAP Beispiele. Dafür haben wir ein neues Paket ZCL_SB_DEMO_RAP_SALES_FIELDS angelegt, wo das Beispiel und das Template liegen. Im Commit findest du alle generierten Artefakte vom heutigen Artikel.
Fazit
Die Generierung per Template erspart dir Arbeit bei der Anlage von RAP Objekten auf bereits existierenden Strukturen, Tabellen oder Entitäten. Dabei verwenden wir den Objekt Generator, um uns für die Schulung ein Template zu erstellen und im zweiten Schritt dann per Generator das RAP Objekt genieren zu lassen.







