
CDS - Writable View Entity
Kannst du einen UPDATE auf einen Core Data Service in ABAP machen? Lass uns dazu die neuen CDS View Entitäten anschauen.
Inhaltsverzeichnis
Wie sieht es eigentlich mit der Aktualisierung von Daten in Datenbanktabellen aus? Gibt es hier schon eine CDS Alternative, wenn die Table Entity noch nicht voll zur Verfügung steht. In diesem Artikel schauen wir uns eine aktuelle Lösung an.
Einleitung
Mit dem Release 2502 wurde im ABAP Environment eine neue Entität im Bereich Core Data Services vorgestellt, die "Writable View Entity". Leider finden wir keine Informationen in den aktuellen News zum ABAP Release 9.14. Auf der Suche nach tiefergehenden Informationen sind wir nur auf einige wenige Links gestoßen und möchten deshalb einfach einmal selbst probieren, was wir aktuell mit den neuen Entitäten machen können.
Vorbereitung
Beginnen wir deshalb erst einmal mit der Anlage einiger Objekte, die wir für den Test benötigen. Dazu legen wir im ersten Schritt eine DDIC Tabelle im System an, die wir zum Schreiben benötigen. Die Tabelle soll eine Firma abbilden, als Schlüssel gibt es eine UUID, dazu Name und Beschreibung, sowie eine Klassifizierung des Unternehmens.
@EndUserText.label : 'Writable Table'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zbs_dmo_write {
key client : abap.clnt not null;
key company_uuid : sysuuid_x16 not null;
name : abap.char(60);
description : abap.sstring(1333);
classification : abap.char(1);
}
Damit wir einige Daten in der Tabelle haben, legen wir uns eine ausführbare Klasse an. Dort befüllen wir eine interne Tabelle mit Daten, löschen die alten Daten und fügen die neuen Daten ein.
CLASS zcl_bs_demo_writable DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PRIVATE SECTION.
METHODS initialize_database
IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.
ENDCLASS.
CLASS zcl_bs_demo_writable IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
initialize_database( out ).
ENDMETHOD.
METHOD initialize_database.
DATA write_database TYPE STANDARD TABLE OF zbs_dmo_write WITH EMPTY KEY.
write_database = VALUE #( ( company_uuid = xco_cp=>uuid( )->value name = 'SAP' classification = 'S' )
( company_uuid = xco_cp=>uuid( )->value name = 'Accenture' classification = 'C' )
( company_uuid = xco_cp=>uuid( )->value name = 'Microsoft' classification = 'S' )
( company_uuid = xco_cp=>uuid( )->value name = 'McKinsey' classification = 'C' )
( company_uuid = xco_cp=>uuid( )->value name = 'Deloitte' classification = 'C' ) ).
DELETE FROM zbs_dmo_write.
INSERT zbs_dmo_write FROM TABLE @write_database.
COMMIT WORK.
out->write( `Data created on database:` ).
out->write( write_database ).
ENDMETHOD.
ENDCLASS.
Im nächsten Schritt legen wir die schreibbare Entität an. Dazu kannst du das Template für die VIEW ENTITY für die Anlage verwenden. Nach der Generierung führen wir die Normalisierung der Datenbankfelder für den Core Data Service durch und fügen das Schlüsselwort WRITABLE zwischen DEFINE und VIEW ein.
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Writable Entity'
define writable view entity ZBS_B_DMOWritable
as select from zbs_dmo_write
{
key company_uuid as CompanyUUID,
name as Name,
description as Description,
classification as Classification
}
Damit ist die Entität nun vollständig definiert. Im nächsten Schritt definieren wir noch ein Access Control für den Test auf dem Core Data Service und beschränken den Zugriff auf die Klassifizierung "C" (Consultant).
@EndUserText.label: 'Access Control'
@MappingRole: true
define role ZBS_B_DMOWRITABLE {
grant
select
on
ZBS_B_DMOWRITABLE
where
Classification = 'C';
}
Damit wären unsere Testartefakte erstellt und wir können im nächsten Schritt dann in den Test einsteigen.
Aktualisierung
In diesem Kapitel schauen wir uns Änderungen auf der Datenbank an, dazu aktualisieren wir die Beschreibung der Unternehmen in verschiedenen Szenarien. Wir verwenden dabei eine Hilfsmethode SELECT_COMPANY_BY_NAME um uns aus der Tabelle, nicht dem Core Data Service, den Datensatz zum Unternehmen zu lesen. Beim Lesen würde das Access Control greifen und nicht alle Daten zurückgeben.
Datenbank
Wir lesen also zuerst den Datensatz und aktualisieren dann die Beschreibung, um die neuen Daten über einen UPDATE an die Datenbank zu geben.
DATA(accenture) = select_company_by_name( 'Accenture' ).
accenture-description = `Accenture plc is a global multinational professional services company`.
UPDATE zbs_dmo_write FROM @accenture.
Writeable Entity (Erlaubt)
Im zweiten Beispiel verwenden wir unsere neue Entität zum Schreiben, wir lesen dabei einen Datensatz, für den wir auch berechtigt wären. Im nächsten Schritt müssen wir die Daten mappen, da wir diese mit den anderen Namen von der Datenbank erhalten. Im Falle eines Core Data Service wäre dieser Schritt nicht mehr nötig. Den UPDATE würden wir genau so durchführen, wie bei der Datenbank.
DATA(deloitte) = select_company_by_name( 'Deloitte' ).
DATA(deloitte_update) = VALUE ZBS_B_DMOWritable(
CompanyUUID = deloitte-company_uuid
Name = deloitte-name
Description = `Deloitte is a multinational professional services network based in London`
Classification = deloitte-classification ).
UPDATE ZBS_B_DMOWritable FROM @deloitte_update.
Writeable Entity (Nicht erlaubt)
Im letzten Beispiel würden wir einen Datensatz lesen, für den wir keine Berechtigungen haben, damit wir die Daten aber für den Update vorbereiten können, lesen wir ihn aus der Tabelle. Dann erfolgt die Aktualisierung der Daten.
DATA(sap) = select_company_by_name( 'SAP' ).
DATA(sap_update) = VALUE ZBS_B_DMOWritable(
CompanyUUID = sap-company_uuid
Name = sap-name
Description = `SAP SE is a European multinational software company based in Walldorf`
Classification = sap-classification ).
UPDATE ZBS_B_DMOWritable FROM @sap_update.
Ergebnis
Wie sieht nun also das Ergebnis der Aktion aus, führen wir die Klasse aus, dann erhalten wir die folgende Ausgabe in die ABAP Konsole. Dabei scheinen alle Updates funktioniert zu haben.
Prüfen wir dann die Inhalte der Tabelle, sehen wir auch, dass alle Unternehmen eine Beschreibung erhalten haben.
Zusammenfassung
Damit sind erst einmal zwei Fakten so weit sicher:
- Über die Writable View Entity können wir Änderungen an die darunterliegende Datenbank weiterleiten.
- Das definierte Access Control limitiert zwar die Anzeige und das Lesen der Daten, aber aktuell nicht das Schreiben.
Die Writable View Entity kann das aktuelle Modell mit Core Data Services ergänzen, da das Mapping der Daten vom Core Data Service Richtung Tabelle entfällt, vor allem wenn kein passendes RAP Objekt verfügbar ist. Die Einschränkung des Schreibzugriffs wird aktuell nicht mit der Entität ausgeliefert, deshalb sollte davor eine Berechtigungsprüfung durchgeführt werden, ob der User die nötigen Berechtigungen hat. Deshalb solltest du dich auch nicht darauf verlassen, dass der Entwickler nur die Hälfte der Daten sehen kann.
Falls du auf die Idee kommen solltest die Modellierung über mehrere Datenquellen zu versuchen, um über einen View vielleicht ein Datenmodell zu aktualisieren, dann funktioniert das aktuell nicht.
Komplettes Beispiel
Die verschiedenen Artefakte findest du in den verschiedenen Kapiteln und Abschnitten oben, hier noch der Vollständigkeit halber die Klasse, die wir für die Ausführung verwenden.
CLASS zcl_bs_demo_writable DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PRIVATE SECTION.
METHODS initialize_database
IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.
METHODS update_database
IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.
METHODS update_writable_allowed
IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.
METHODS select_company_by_name
IMPORTING !name TYPE zbs_dmo_write-name
RETURNING VALUE(result) TYPE zbs_dmo_write.
METHODS handle_update_result
IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.
METHODS update_writable_not_allowed
IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.
ENDCLASS.
CLASS zcl_bs_demo_writable IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
initialize_database( out ).
update_database( out ).
update_writable_allowed( out ).
update_writable_not_allowed( out ).
ENDMETHOD.
METHOD initialize_database.
DATA write_database TYPE STANDARD TABLE OF zbs_dmo_write WITH EMPTY KEY.
write_database = VALUE #( ( company_uuid = xco_cp=>uuid( )->value name = 'SAP' classification = 'S' )
( company_uuid = xco_cp=>uuid( )->value name = 'Accenture' classification = 'C' )
( company_uuid = xco_cp=>uuid( )->value name = 'Microsoft' classification = 'S' )
( company_uuid = xco_cp=>uuid( )->value name = 'McKinsey' classification = 'C' )
( company_uuid = xco_cp=>uuid( )->value name = 'Deloitte' classification = 'C' ) ).
DELETE FROM zbs_dmo_write.
INSERT zbs_dmo_write FROM TABLE @write_database.
COMMIT WORK.
out->write( `Data created on database:` ).
out->write( write_database ).
ENDMETHOD.
METHOD select_company_by_name.
SELECT SINGLE FROM zbs_dmo_write
FIELDS *
WHERE name = @name
INTO @result.
ENDMETHOD.
METHOD update_database.
DATA(accenture) = select_company_by_name( 'Accenture' ).
accenture-description = `Accenture plc is a global multinational professional services company`.
out->write( 'Table ZBS_DEMO_WRITE' ).
UPDATE zbs_dmo_write FROM @accenture.
handle_update_result( out ).
ENDMETHOD.
METHOD update_writable_allowed.
DATA(deloitte) = select_company_by_name( 'Deloitte' ).
DATA(deloitte_update) = VALUE ZBS_B_DMOWritable(
CompanyUUID = deloitte-company_uuid
Name = deloitte-name
Description = `Deloitte is a multinational professional services network based in London`
Classification = deloitte-classification ).
out->write( 'CDS ZBS_B_DMOWritable (Allowed)' ).
UPDATE ZBS_B_DMOWritable FROM @deloitte_update.
handle_update_result( out ).
ENDMETHOD.
METHOD update_writable_not_allowed.
DATA(sap) = select_company_by_name( 'SAP' ).
DATA(sap_update) = VALUE ZBS_B_DMOWritable(
CompanyUUID = sap-company_uuid
Name = sap-name
Description = `SAP SE is a European multinational software company based in Walldorf`
Classification = sap-classification ).
out->write( 'CDS ZBS_B_DMOWritable (Not allowed)' ).
UPDATE ZBS_B_DMOWritable FROM @sap_update.
handle_update_result( out ).
ENDMETHOD.
METHOD handle_update_result.
IF sy-subrc = 0.
out->write( |Update was successful: { sy-subrc }| ).
COMMIT WORK.
ELSE.
out->write( |Update was not successful: { sy-subrc }| ).
ROLLBACK WORK.
ENDIF.
ENDMETHOD.
ENDCLASS.
Fazit
Schreiben der Daten im Format des Core Data Services? Mit der Writable View Entity nun möglich, die neben der Table Entity als Ergänzung für die klassischen Tabellen fugieren könnte, ohne eine große Migrationswelle lostreten zu müssen.
Weitere Informationen:
SAP Community - ABAP News for SAP BTP ABAP Environment 2502
SAP Help - Writable View Entities