
BTP - Anbindung On-Premise (SQL Service)
Wie können wir einen SQL Service On-Prem mit unserem ABAP Environment verbinden und welche Vorteile haben wir damit? Gehen wir einmal auf technischen Deep Dive.
Inhaltsverzeichnis
In diesem Artikel kümmern wir uns um die Anbindung eines SQL-Services in der BTP. Dabei werden wir verschiedene Schritte durchgehen, um die Konfiguration zu erzeugen, die externe Entität anzulegen und später die Verbindung herzustellen.
Einleitung
Für die Erstellung von Side-by-Side Szenarien ist die Anbindung verschiedener Services und Techniken entscheidend, um solche Szenarien abzubilden. Dabei haben wir uns in der Vergangenheit bereits OData, RFC und native Anbindungen angeschaut. Eine Technologie, die relativ aktuell ist und die vor allem sehr viel im Bereich der RAP-Modellierung verspricht, sind die sogenannten SQL-Services. Diese sind bereits seit älteren Releases auch On-Prem verfügbar und können auch als Datenquelle genutzt werden. Daher schauen wir einmal auf die Verwendung dieser Art von Services und wie wir diese vor allem im ABAP Environment nutzen können.
SQL Service
Für den Aufbau des SQL-Services verwenden wir ein S/4HANA 2023 Release, welches bereits SQL-Services im SELECT-Case anbietet. Besitzt du bereits ein Release 2025, stehen mehr Funktionen zur Verfügung, die du im SQL-Service aktivieren kannst. Damit wäre auch ein Schreiben auf diesem Service möglich. Der SQL-Service bietet einfache Operationen auf sogenannten Datenquellen an, die das Lesen und später auch Schreiben ermöglichen sollen, um somit einen nativen, einfachen und schnellen Zugriff auf Datenquellen innerhalb eines SAP-Systems zu ermöglichen. Als Basis können wir hier auf Core Data Services zurückgreifen und in der Definition auch zum Beispiel ein Access Control nutzen, um einen sicheren Zugriff auf die Daten und die Datenquelle zu ermöglichen.
In diesem Szenario definieren wir auf unserer Service-Definition ZBS_DEMO_PERFROMANCE_DATA, die wir bereits für unseren Performance-Test genutzt haben, ein neues Service-Binding vom Typ "SQL - Web API".
Den SQL-Service musst du nach der Anlage nicht aktivieren, dieser ist automatisch verfügbar und durch entsprechende Berechtigungen geschützt. Wenn du im Service genauer hinschaust, siehst du die verfügbaren SQL-Operationen, hier entsprechend nur SELECT. In modernen System findest du hier auch verschiedene Checkboxen zum Aktivieren und Deaktivieren der verschiedenen CRUD-Operationen.
External Entity
Grundsätzlich kannst du die externe Entität in der BTP nun auch von Hand anlegen oder per Copy-and-paste. Handelt es sich aber um eine große Anzahl von Entitäten, sind diese komplex oder haben verschiedene Datentypen, lohnt es sich schon, eine Definition per JSON aus dem System zu ziehen. Daher schauen wir uns in diesem Kapitel an, wie wir die Definition erzeugen und für die BTP zur Verfügung stellen.
Erzeugung
Dazu rufen wir im aktuellen System, wo auch der SQL-Service angelegt wurde, die Transaktion SCSN_EXPORT_COCKPIT auf, um uns die Definition des Modells zu extrahieren.
Hier geben wir den SQL-Service unter dem Punkt "Services" an, da wir diesen auch wirklich vollständig extrahieren wollen und zwar mit allen Entitäten. Du kannst dich auch entscheiden, ob du die Typen mit exportieren willst. Das bedeutet wiederum, im Zielsystem werden entsprechende Simple Types für die Typisierung angelegt. In diesem Fall wollen wir ohne Typen extrahieren. Das heißt, in unserem Zielsystem wird eine externe Entität angelegt und normale ABAP-Typen für die Definition verwendet.
Bist du soweit mit den Einstellungen fertig, kannst du über den Start-Button die Extraktion durchführen. Im nächsten Schritt wird eine JSON-Datei erzeugt und diese in einem Pop-up aufbereitet und angezeigt. Dabei kannst du prüfen, ob der Extrakt dem entspricht, was du auch im Zielsystem anlegen möchtest und kannst dann wiederum den Inhalt des Pop-ups als lokale JSON-Datei auf deinem System ablegen. Die Datei benötigen wir dann für den nächsten Schritt.
Definition
Im nächsten Schritt legen wir ein sogenanntes "Core Schmea Notation Model" an, welches wir als Artefakt im System benötigen, um unsere CSN-Datei von unserem System zu importieren. Du findest das Objekt im Bereich "Others", wenn du nach allen Repository-Objekten suchst. Hier vergibst du einen Namen und eine Beschreibung für das Objekt, wie der Name lautet, ist in diesem Fall nicht ganz so wichtig.
Über den "Add"-Button im UI können wir dann unsere Datei ins System laden. Dabei müssen wir auch noch einen Namen für die Datei vergeben, in dem Fall vergeben wir eine einfache Identifikation mit "Performance". Dieser Name ist ebenfalls nicht ganz so wichtig, da die Information aus der eigentlichen Datei kommt, die wir hochladen. Zum Abschluss müssen wir das Objekt noch sichern, damit alle Änderungen am Objekt vorhanden sind.
Generierung
Nun können wir mit der Generierung der eigentlichen Artefakte, also der externen Entität im System, beginnen. Der einfachste Weg, den Generator zu starten, ist per Rechtsklick auf das zuvor angelegte Objekt. Dort findest du den Generator im Kontextmenü unter dem Punkt "Generate ABAP Repository Objects ..." und startest diesen im System.
Im nächsten Abschnitt spezifizieren wir den eigentlichen Generator, den wir starten wollen. Da wir von einem bestimmten Objekttyp aus gestartet sind, werden die verfügbaren Generatoren bereits auf die relevanten Möglichkeiten eingeschränkt. Da wir einen SQL-Service im Hintergrund haben, wollen wir ein "ABAP SQL Consumption Model" anlegen.
Im nächsten Abschnitt finden wir die eigentliche Konfiguration aller zu definierenden Entitäten und Elemente, die das System erzeugen möchte. Hier kannst du durch die verschiedenen Reiter klicken und schauen, ob die Namenskonventionen für dich passen und ob die Objekte so angelegt werden können. In diesem Fall haben wir zum Beispiel noch den Namen des Core Data Service auf die externe Entität angepasst. Weitere Anpassungen haben wir nicht vorgenommen.
Zum Abschluss wird der Generator ausgeführt und die Objekte werden im Hintergrund erzeugt. Hier funktioniert der Generator ähnlich wie der RAP-Generator und es kann je nach Anzahl der Entitäten etwas dauern, bis diese generiert werden. Ist die Generierung abgeschlossen, erhalten wir ein Pop-up und können direkt zu unseren Entitäten navigieren.
Die erste Version der externen Entität wurde im System angelegt und wir finden bereits alle nötigen Attribute, wie Mappings, direkt in der Entität wieder. Grundsätzlich würden wir die Namen hier eins zu eins verwenden, wie wir sie auch On-Prem verwenden, da wir hier bereits einen Core Data Service mit entsprechenden langen Namen und Formatierungen nutzen. Wie wir auf den ersten Blick sehen, wurden auch bereits erste Annotationen übernommen, wie zum Beispiel der Currency Code oder ein entsprechendes Label aus dem Backend. Grundsätzlich sind alle Typen eingebaute ABAP-Typen, die hier verwendet werden, so wie wir es bei der Extraktion angegeben haben.
define external entity ZBS_X_DemoSQLPerformance external name "Performance"
{
@EndUserText.label: 'UUID'
@EndUserText.quickInfo: '16 Byte UUID in 16 Bytes (Raw Format)'
key Identifier : abap.raw( 16 ) external name "Identifier";
ItemDescription : abap.char( 40 ) external name "ItemDescription";
RandomDescription : abap.char( 150 ) external name "RandomDescription";
@Semantics.amount.currencyCode: 'Currency'
Amount : abap.decfloat34 external name "Amount";
Currency : abap.cuky external name "Currency";
BlobObject : abap.string( 0 ) external name "BlobObject";
NewDate : abap.char( 8 ) external name "NewDate";
NewTime : abap.char( 6 ) external name "NewTime";
UTCTimestamp : abap.utclong external name "UTCTimestamp";
}
with federated data provided at runtime
Hinweis: Dies war jetzt eine sehr große Anzahl von Schritten, die wir durchgeführt haben, um die externe Entität im System zu generieren. Grundsätzlich kann die Anlage auch von Hand erfolgen, dort müssen einfach die Typen übernommen werden, so wie sie entsprechend definiert sind. Eine Generierung kann durchaus Sinn ergeben, wenn es sich um eine sehr große Anzahl an Entitäten handelt.
Konfiguration
In diesem Artikel werden wir nicht noch mal auf die grundsätzliche Beschreibung der Einrichtung der Konfiguration eingehen. Dazu gibt es einen älteren Artikel, in dem genau beschrieben wird, wie Schritt für Schritt die Konfigurationen anzulegen sind. In diesem Artikel verwenden wir das gleiche Szenario, sodass wir eine HANA Cloud-Datenbank in der Mitte haben, über die wir zugreifen werden. Richtung On-Prem werden wir über den Cloud Connector gehen. In der aktuellen Architektur ist keine direkte Verbindung von der HANA-Datenbank des ABAP Environments gegen den Cloud Connector möglich, da die Konfiguration nicht bekannt ist. Wie auch im Artikel beschrieben, legen wir eine virtuelle Tabelle auf der HANA Cloud-Instanz an, die wir als Basis nutzen, um später den Zugriff auf die On-Prem Datenbank und den Hopp zu realisieren.
Auf Seite des ABAP Environments legen wir dann auch einen entsprechenden Outbound SQL Service an und definieren diesen für den Zugriff Richtung On-Prem.
Im Communication Scenario muss dann der Service als Outbound SQL Access angelegt werden, sodass dieser dann auch im System berechtigt werden kann und die Konfiguration gegen das Communication System erfolgen kann. Alle anderen Einstellungen und Beschreibungen findest du im verlinkten Artikel, der noch einmal im Detail die Anbindung beschreibt.
Anpassungen
Grundsätzlich können wir nun mit dem Test der externen Entität beginnen. Allerdings wollen wir hier noch einige Anpassungen vornehmen, damit der eigentliche Test funktioniert.
- Zum einen wollen wir die Zugriffsart ändern. Hier verwenden wir den PROVIDED BY Zusatz, da wir direkt in der Entität sagen wollen, über welches Schema der Zugriff erfolgen soll.
- Als zweiten Punkt ändern wir dann die Annotationen und setzen die Authorization-Annotation, die wir dann benötigen, da wir das Szenario gewechselt haben.
- Als Drittes müssen wir noch den Datentyp für das Betragsfeld anpassen, da wir sonst später eine Fehlermeldung aus dem Service erhalten. Die Extraktion hat hier den Datentyp decfloat34 verwendet, der allerdings zu Problemen führt, da er nicht dem Datentyp der virtuellen Tabelle entspricht. Schauen wir uns die virtuelle Tabelle noch einmal im Detail an, dann wurde hier ein Datentyp von DEC(15,2) angelegt, daher müssen wir den Typen noch anpassen.
- Als letzten Schritt müssen wir den Namen der externen Entität noch anpassen. Das liegt daran, dass wir auf der HANA Cloud eine entsprechende virtuelle Tabelle definiert haben, die einen eigenen Alias hat. Diesen Alias kennt der Generator nicht, daher passen wir hier den Namen auf den Alias der HANA Cloud an.
@AccessControl.authorizationCheck: #NOT_REQUIRED
define external entity ZBS_X_DemoSQLPerformance external name "PERFORMANCE"
{
@EndUserText.label: 'UUID'
@EndUserText.quickInfo: '16 Byte UUID in 16 Bytes (Raw Format)'
key Identifier : abap.raw( 16 ) external name "Identifier";
ItemDescription : abap.char( 40 ) external name "ItemDescription";
RandomDescription : abap.char( 150 ) external name "RandomDescription";
@Semantics.amount.currencyCode: 'Currency'
Amount : abap.dec( 15, 2 ) external name "Amount";
Currency : abap.cuky external name "Currency";
BlobObject : abap.string( 0 ) external name "BlobObject";
NewDate : abap.char( 8 ) external name "NewDate";
NewTime : abap.char( 6 ) external name "NewTime";
UTCTimestamp : abap.utclong external name "UTCTimestamp";
}
with federated data provided by ZBS_DEMO_PERF_EXT_SCHEMA
Test
Haben wir die Anpassung durchgeführt, können wir unsere eigentliche Testklasse schreiben. Diese fällt relativ unspektakulär aus, da wir hier einfach einen SELECT gegen die externe Entität machen, so wie wir ihn bereits von jedem SELECT gegen eine normale Datenbank kennen. Wir benötigen in diesem Fall kein Schema oder sonstige externe Zusätze, sondern machen einen einfachen SELECT, um die Daten zu lesen, und geben diese dann in der Konsole aus. Hier folgt ein entsprechendes Fehlerhandling, da wir bei unseren Tests noch Fehler im Mapping hatten. Grundsätzlich hilft es, besser zu verstehen, welche Fehlermeldungen aus dem Zugriff heraus entstehen. Hier solltest du dir den kompletten Exception-Stack einmal genauer anschauen, meistens ist die erste erzeugte Ausnahme diejenige, in der die wirkliche Fehlermeldung enthalten ist.
CLASS zcl_bs_demo_hana_perf_test DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
ENDCLASS.
CLASS zcl_bs_demo_hana_perf_test IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
TRY.
SELECT FROM ZBS_X_DemoSQLPerformance
FIELDS *
INTO TABLE @DATA(remote_datas)
UP TO 50 ROWS.
out->write( remote_datas ).
CATCH cx_root INTO DATA(sql_runtime).
out->write( sql_runtime ).
ENDTRY.
ENDMETHOD.
ENDCLASS.
Führen wir die Klasse dann einmal aus, erhalten wir die ersten 50 Datensätze in der Konsole. Diese entsprechen den Performance-Daten aus unserem On-Prem System. Damit ist der eigentliche Test und die Anbindung abgeschlossen. Wir können nun über einfache SELECT-Statements direkt über die externe CDS-Entität die Daten lesen.
Da das logische externe Schema bereits im Core Data Service hinterlegt ist, können wir auch direkt den Data Preview mit F8 auf dem CDS-View ausführen. Dadurch wird die Vorschau geladen und die Daten direkt darin angezeigt, ohne dass wir manuell eine Verbindung aufbauen müssen. Im Tool können wir dann weiterhin passende Filter setzen, Daten über Filter selektieren und uns anzeigen lassen, so wie wir es von einer lokalen Tabelle gewohnt sind.
Fazit
Die Anbindung per externer Entität ist nun erfolgt und wir haben den Remote-SQL-Service verbunden. Die neu erstellte externe Entität agiert im System wie eine lokale Tabelle. Allerdings merkt man hier schon einige kleinere Performance-Unterschiede im Vergleich zu einer echten lokalen Tabelle die auf der gleichen HANA Datenbank liegt. Grundsätzlich ist dies aber eine sehr effiziente Methode, um Remote auf Daten zuzugreifen.















