RAP - Entity Manipulation Language (EML)
In diesem Artikel beschäftigen wir uns mit einem neuen Sprachkonstrukt zum Zugriff auf unser RAP Business Objekt.
Inhaltsverzeichnis
Wie greift man leicht von außen auf ein Business Objekt zu und was bringt es mit sich mit? In diesem Artikel erfährst du mehr über das neue Sprachkonstrukt EML und was dahintersteht. Wir versuchen dir die Grundbegriffe und die ersten Möglichkeiten zu zeigen, die EML dir zur Verfügung stellt.
EML
Die Entity Manipulation Language ist ein neues SQL-artiges Sprachkonstukt, welches dir Zugriffe auf RAP Business Objekte und deren Daten ermöglicht. Dabei werden alle Validierungen, Ermittlungen und sonstige Einstellungen berücksichtigt, sodass du die gleichen Funktionen hast, wie mit der Fiori App. Beim Verwenden erhältst du auch vollen Support auf Aktionen und die Draft Funktionen, wenn diese im Objekt konfiguriert sind.
Lesen
In diesem Abschnitt gehen wir auf das Lesen von Daten aus einem Objekt ein, dabei musst du beachten, dass es sich um keinen SELECT handelt, sondern eher um einen READ. Wir müssen also vorher auf einem Weg die passenden Schlüssel lesen, es gibt aktuell noch keine Query Funktion für Business Objekte.
Schauen wir uns dazu zwei unterschiedliche Formen des Zugriffs an, die sich im Detail etwas unterscheiden. Im ersten Beispiel lesen wir alle Daten zu einem Datensatz und befüllen die Selektionstabelle vor dem Zugriff:
DATA:
lt_selection TYPE TABLE FOR READ IMPORT ZBS_I_RAPPartner.
lt_selection = VALUE #(
( PartnerNumber = '1000000001' )
( PartnerNumber = '1000000003' )
).
READ ENTITIES OF ZBS_I_RAPPartner ENTITY Partner
ALL FIELDS WITH lt_selection
RESULT DATA(lt_partner_long)
FAILED DATA(ls_failed)
REPORTED DATA(ls_reported).
out->write( lt_partner_long ).
Dazu definieren wir zu Beginn eine Tabelle für den Zugriff, die die passenden Partnernummern enthält, die wir Lesen wollen. Im Anschluss rufen wir READ ENTITIES auf, um uns für die Selektion das Ergebnis zurückgeben zu lassen. Das zweite Beispiel ist etwas kürzer, da wir die Selektion direkt übergeben. In diesem Beispiel lesen wir nur einige Felder der Entität aus:
READ ENTITIES OF ZBS_I_RAPPartner ENTITY Partner
FIELDS ( PartnerName Street City ) WITH VALUE #(
( PartnerNumber = '1000000001' )
( PartnerNumber = '1000000003' )
)
RESULT DATA(lt_partner_short)
FAILED ls_failed
REPORTED ls_reported.
out->write( lt_partner_short ).
Nachdem die Selektion durchgeführt wurde und die Ausgabe in die Console erfolgt ist, erhältst du das folgende Ergebnis. Das obere Ergebnis ist die Langform, unten die Kurzform. Die erzeugten Ergebnistabelle repräsentieren immer die gesamte Entität:
Was hat es nun also mit den einzelnen Bestandteilen des Statements auf sich, hier kurz erklärt:
- READ ENTITIES - Angabe des RAP Business Objekt, entspricht meist dem Root Knoten des Objekts.
- ENTITY - Angabe der zu lesenden Entität aus dem RAP Objekt, hier kommt vor allem der Alias der Entität zum Tragen.
- FIELDS - Angabe der zu lesenden Felder als Tabelle, Ausdruck der Felder oder aller Felder.
- WITH - Übergabe der Schlüssel an die Lesefunktion, Tabelle wird mit "TABLE FOR READ IMPORT" definiert.
- RESULT - Tabelle mit den gelesenen Daten, kann per Inline-Deklaration angelegt werden und besitzt den Typ "TABLE FOR READ RESULT".
- FAILED - Schlüssel der fehlerhaften Einträge, wenn das Lesen nicht geklappt hat.
- REPORTED - Enthält Fehlermeldungen, wenn es beim Lesen zu Problemen kam.
Anlegen
Im nächsten Schritt wollen wir einmal einen neuen Datensatz anlegen, dazu gibt es das Statement MODIFY ENTITIES, welches alle wichtigen Operationen (Create, Update, Delete, Action) enthält. In unserem Beispiel befüllen wir wieder eine Tabelle, dieses mal vom Typ "TABLE FOR CREATE", da wir ja einen neuen Datensatz anlegen wollen. Dazu das folgende Beispiel:
DATA:
lt_creation TYPE TABLE FOR CREATE ZBS_I_RAPPartner.
lt_creation = VALUE #(
(
%cid = 'DummyKey1'
PartnerNumber = '1000000007'
PartnerName = 'Amazon'
Country = 'US'
%control-PartnerNumber = if_abap_behv=>mk-on
%control-PartnerName = if_abap_behv=>mk-on
%control-Country = if_abap_behv=>mk-on
)
).
MODIFY ENTITIES OF ZBS_I_RAPPartner ENTITY Partner
CREATE FROM lt_creation
FAILED ls_failed
MAPPED DATA(ls_mapped)
REPORTED ls_reported.
TRY.
out->write( ls_mapped-partner[ 1 ]-PartnerNumber ).
COMMIT ENTITIES.
CATCH cx_sy_itab_line_not_found.
out->write( ls_failed-partner[ 1 ]-%cid ).
ENDTRY.
Was dir bei der Befüllung der Tabelle auffällt ist, dass wir nicht nur die Datenfelder übernehmen, sondern auch die CID und CONTROL Felder befüllen. Diese Felder sind wichtig, damit die Daten im Objekt sauber übernommen werden:
- %CID - Dummy ID die einen Datensatz innerhalb von Create, Update und Delete identifiziert. Kann frei vergeben werden, soll aber eindeutig sein.
- %CONTROL - Angabe welche Felder bei der Operation berücksichtigt werden. Sind die Felder in der Struktur nicht aktiv, werden keine Daten übernommen und der neue Datensatz ist leer.
- MAPPED - Rückgabe der geänderten Schlüssel und Zuordnung von CID zu Tabellenschlüssel. Vor allem dann wichtig, wenn die Schlüssel innerhalb des Business Objekts generiert werden.
Zum Abschluss wird der neue Schlüssel ins Log ausgegeben und ein COMMIT ENTITIES abgesetzt, dies entspricht in etwa dem COMMIT WORK im ABAP, wird aber speziell für die RAP Operationen eingesetzt.
Aktualisieren
Im letzten Schritt haben wir einen relativ unvollständigen Datensatz auf der Datenbank erzeugt, den wir nun mit einigen Daten anreichern wollen. Dazu für die Ausgangslage noch den aktuellen Datensatz auf der Datenbank:
Wir definieren dazu eine Tabelle vom Typen "TABLE FOR UPDATE", passend zur Aktion und befüllen die benötigten Felder. Für den Update müssen wir keine CID angeben, da der Schlüssel bereits bekannt ist. Allerdings sollten wir auch den passenden Schlüssel angeben. Weiterhin ist wieder die CONTROL Struktur wichtig. Das ergibt den folgenden Code:
DATA:
lt_update TYPE TABLE FOR UPDATE ZBS_I_RAPPartner.
lt_update = VALUE #(
(
PartnerNumber = '1000000007'
PartnerName = 'Amazon Fake'
City = 'Seattle'
PaymentCurrency = 'USD'
%control-PaymentCurrency = if_abap_behv=>mk-on
%control-City = if_abap_behv=>mk-on
)
).
MODIFY ENTITIES OF ZBS_I_RAPPartner ENTITY Partner
UPDATE FROM lt_update
FAILED ls_failed
MAPPED ls_mapped
REPORTED ls_reported.
IF ls_failed-partner IS INITIAL.
out->write( 'Updated' ).
COMMIT ENTITIES.
ENDIF.
Wie du oben im Beispiel siehst, übergeben wir auch einen neuen Namen für den Partner, befüllen aber nicht die CONTROL Struktur. Wir gehen also davon aus, dass das Feld Name nicht aktualisiert wird und den originalen Wert behält. Nach Ausführung des Codes erhalten wir das folgende Ergebnis und unsere Vermutung bewahrheitet sich:
IF_ABAP_BEHV
In unseren Beispielen hatten wir bereits Konstanten aus dem Interface IF_ABAP_BEHV verwendet. Das Interface stellt verschiedene Konstanten für die Nutzung rund um die Verhaltensimplementierung zur Verfügung und gibt über ABAP Docs auch Hinweise, wo diese Konstanten genutzt werden können. Hier im Beispiel der verwendeten MK Konstanten:
Verwendung
Wo benötigt man eigentlich überall EML? Vor allem setzt man es beim externen Zugriff auf das Business Objekt ein, so wie aktuell unsere Beispiele aufgebaut sind. Später wird es viele RAP Objekte geben, die als BAPI im System fungieren, dann muss man sie über diesen Weg ansprechen. Weiterhin setzt man RAP auch innerhalb des Business Objekts ein, wenn man Validierungen, Ermittlungen oder Aktionen implementiert, da man dort immer wieder auf Daten des BOs zugreifen und diese verändern muss.
Komplettes Beispiel
Wie immer am Ende noch den kompletten Quellcode des Beispiels, das Ganze findest du auch per Commit im entsprechenden GitHub Repository von uns:
CLASS zcl_bs_demo_simple_eml DEFINITION PUBLIC FINAL CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_bs_demo_simple_eml IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA:
lt_selection TYPE TABLE FOR READ IMPORT ZBS_I_RAPPartner,
lt_creation TYPE TABLE FOR CREATE ZBS_I_RAPPartner,
lt_update TYPE TABLE FOR UPDATE ZBS_I_RAPPartner.
" Long form for selection (ALL FIELDS)
lt_selection = VALUE #(
( PartnerNumber = '1000000001' )
( PartnerNumber = '1000000003' )
).
READ ENTITIES OF ZBS_I_RAPPartner ENTITY Partner
ALL FIELDS WITH lt_selection
RESULT DATA(lt_partner_long)
FAILED DATA(ls_failed)
REPORTED DATA(ls_reported).
out->write( lt_partner_long ).
" Short form for selection (SOME FIELDS)
READ ENTITIES OF ZBS_I_RAPPartner ENTITY Partner
FIELDS ( PartnerName Street City ) WITH VALUE #(
( PartnerNumber = '1000000001' )
( PartnerNumber = '1000000003' )
)
RESULT DATA(lt_partner_short)
FAILED ls_failed
REPORTED ls_reported.
out->write( lt_partner_short ).
" Create new partner
lt_creation = VALUE #(
(
%cid = 'DummyKey1'
PartnerNumber = '1000000007'
PartnerName = 'Amazon'
Country = 'US'
%control-PartnerNumber = if_abap_behv=>mk-on
%control-PartnerName = if_abap_behv=>mk-on
%control-Country = if_abap_behv=>mk-on
)
).
MODIFY ENTITIES OF ZBS_I_RAPPartner ENTITY Partner
CREATE FROM lt_creation
FAILED ls_failed
MAPPED DATA(ls_mapped)
REPORTED ls_reported.
TRY.
out->write( ls_mapped-partner[ 1 ]-PartnerNumber ).
COMMIT ENTITIES.
CATCH cx_sy_itab_line_not_found.
out->write( ls_failed-partner[ 1 ]-%cid ).
ENDTRY.
" Update partner
lt_update = VALUE #(
(
PartnerNumber = '1000000007'
PartnerName = 'Amazon Fake'
City = 'Seattle'
PaymentCurrency = 'USD'
%control-PaymentCurrency = if_abap_behv=>mk-on
%control-City = if_abap_behv=>mk-on
)
).
MODIFY ENTITIES OF ZBS_I_RAPPartner ENTITY Partner
UPDATE FROM lt_update
FAILED ls_failed
MAPPED ls_mapped
REPORTED ls_reported.
IF ls_failed-partner IS INITIAL.
out->write( 'Updated' ).
COMMIT ENTITIES.
ENDIF.
ENDMETHOD.
ENDCLASS.
Fazit
Mit EML gilt es erst einmal einige neue Sprachkonstrukte zu lernen und wie diese genau funktionieren. Auch die neuen Tabellentypen können am Anfang erst einmal überfordern und einige Inhalte machen erst einmal keinen Sinn. Doch wenn du erst einmal in der Sprache drin bist, macht es Spaß damit zu arbeiten. In einem späteren Artikel werden wir noch tiefer in das Thema EML einsteigen, hier erst einmal nur die Grundlagen für die folgenden Artikel.