
RAP - Draft Query
In diesem Artikel schauen wir uns die Draft Query in RAP an und wie du damit die Einträge und ihre Sichtbarkeit steuern kannst. Dazu schauen wir uns die Praxis an einem Beispiel an.
Inhaltsverzeichnis
In diesem Artikel werden wir vor allem auf den Draft Scope eingehen und wie du damit den eigentlichen Draft steuern kannst.
Einleitung
Aktuell haben wir in unserer Sales App eine Tabelle für die beteiligten Verkäufer auf der Object Page. In der Tabelle wollen wir neue Verkäufer hinzufügen und können über die Aktion nicht bestätigte Einträge freigeben oder einen Workflow dazu starten, der den eigentlichen Freigabeprozess auslöst.
Hinweis: Über diesen Commit haben wir die Release Aktion von den verkauften Materialien auf die Verkäufer umgestellt, da diese nur dafür gedacht war.
Anforderung
Nun haben wir noch eine Anforderung, dass im aktiven Zustand der Instanz nur die bestätigten Einträge zu sehen sind und wenn wir den Datensatz editieren, dann sollen jeweils nur neue und nicht freigegebene Sätze pflegbar sein. Einmal freigegeben können die anderen Datensätze nicht mehr editiert werden und sollen auch nicht mehr sichtbar sein.
Prüfung
Um die Datensätze für die Ausgabe zu filtern, haben wir aktuell mehrere Möglichkeiten. Zum einen können wir einen harten Filter in die WHERE Clause des Core Data Service übernehmen, damit würde niemand mehr an die nicht freigegebenen Datensätze kommen, da die Bedingung immer greift. Oder wir erweitern die Berechtigungsprüfung und fügen dort eine Kondition ein. Damit haben wir die Möglichkeit später mit PRIVILIGED ACCESS auf die Daten zugreifen zu können. Daher wählen wir die zweite Variante und erweitern das Access Control, welches mit dem RAP Generator angelegt wurde. Dazu öffnen wir ZBS_R_SASELLER und passen die Bedingung an, die neue Implementierung sollte nun wie folgt aussehen:
@EndUserText.label: 'ZBS_R_SASELLER'
@MappingRole: true
define role ZBS_R_SASELLER {
grant select on ZBS_R_SASELLER
where Confirmed = 'X';
}
Der Projection Layer erbt von diesem View und damit auch die Prüfung. Rufen wir nun die gleiche Entität auf und lassen uns die Verkäufer anzeigen. Es wird nur noch ein Datensatz geladen, der auch wirklich freigegeben wurde.
Gehen wir nun in den Edit Mode, dann sehen wir wieder alle Datensätze und können auch die freigegebenen Datensätze wieder editieren. Das eigentliche Access Control unseren Projection Layers greift damit nicht mehr und wir sehen den kompletten Draft.
Draft Query
In diesem Kapitel gehen wir auf eine Lösung für unsere aktuelle Situation ein.
Ursache
Was ist eigentlich im oberen Beispiel passiert? Beim Klick auf "Edit" im UI gehen wir in die Bearbeitung und der komplette Originalsatz und alle abhängigen Entitäten werden in die Draft Tabellen geladen die im RAP Objekt definiert sind.
Damit können wir am Draft arbeiten, ohne das Original zu beeinflussen. Allerdings werden aktuell die Daten nur aus der Draft Tabelle gelesen und hier haben wir keine weitere Möglichkeit die Daten einzuschränken. Ein Access Control kann nicht auf einer Tabelle definiert werden.
Query
Als Lösung definieren wir uns auf der Draft Tabelle ZBS_SASELLER_D einen eigenen Core Data Service, wo wir auch eine entsprechende Berechtigung definieren können. Den View kannst du direkt über das Kontextmenü im Project Explorer als CDS Artefakt anlegen. Das Mapping der Felder machen wir beim eigentlichen View auf Interface Ebene.
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Draft for Seller'
define view entity ZBS_I_SASellerDraft
as select from zbs_saseller_d
{
key uuid as UUID,
parentuuid as ParentUUID,
sellerid as SellerId,
quota as Quota,
confirmed as Confirmed,
draftentitycreationdatetime as Draftentitycreationdatetime,
draftentitylastchangedatetime as Draftentitylastchangedatetime,
draftadministrativedatauuid as Draftadministrativedatauuid,
draftentityoperationcode as Draftentityoperationcode,
hasactiveentity as Hasactiveentity,
draftfieldchanges as Draftfieldchanges
}
Zu dem neuen Query erzeugen wir uns ebenfalls über das Kontext Menü des neuen Core Data Service ein Access Control und definieren hier wieder eine einfache Bedingung.
@EndUserText.label: 'Draft Scope'
@MappingRole: true
define role ZBS_I_SASELLERDRAFT {
grant
select
on
ZBS_I_SASELLERDRAFT
where
Confirmed is initial;
}
Verhalten
In der Verhaltensdefinition ZBS_R_SASALE ergänzen wir nun hinter der Draft Tabelle den Core Data Service per QUERY. Damit wird beim Laden des Draft die Query für die Ermittlung verwendet und damit auch unser Access Control.
define behavior for ZBS_R_SASELLER alias SASeller
persistent table zbs_saseller
extensible
draft table zbs_saseller_d query ZBS_I_SASellerDraft
etag dependent by _SASale
lock dependent by _SASale
authorization dependent by _SASale
Test
Gehen wir zurück in unsere Anwendung und rufen den Datensatz im Änderungsmodus auf, dann werden nur noch zwei Datensätze angezeigt. Der aktive Datensatz wird nun über das Access Control ausgeblendet, ist aber weiterhin in der Draft Tabelle enthalten.
Aktion
Um nun noch die Logik zu vervollständigen, implementieren wir die eigentliche Action, die die Freigabe durchführen soll.
Update
Für den einfachen Update müssen wir nicht einmal viel Logik schreiben. Da wir direkt die Schlüssel nehmen, um ein Kennzeichen umzusetzen, reicht uns im ersten Schritt der Schlüssel und wir können direkt den Update aufrufen. Dazu verwenden wir eine FOR Schleife und übernehmen alle übergebenen Datensätze.
MODIFY ENTITIES OF zbs_r_sasale IN LOCAL MODE
ENTITY SASeller
UPDATE FIELDS ( Confirmed )
WITH VALUE #( FOR key IN keys
( %tky = key-%tky Confirmed = abap_true ) )
MAPPED mapped.
UI
Nach der Ausführung der Aktion passiert allerdings noch nichts in unserer Anwendung. Der Datensatz wurde nicht aktualisiert und auch nicht ausgeblendet. Aktuell ändern wir zwar den Datensatz im Puffer und Draft, allerdings geben wir der Oberfläche keinen Trigger sich zu aktualisieren. Daher erweitern wir die Aktion und geben den Datensatz selbst zurück, damit kann sich das UI über die neuen Daten selbst aktualisieren.
action ReleaseItems result [1] $self;
In der eigentlichen Implementierung lesen wir zum Abschluss noch einmal den aktuellen Datensatz nach und mappen das Ergebnis auf das nun verfügbare Feld RESULT. Ob du das Mapping per LOOP oder FOR machst, bleibt am Ende dir überlassen.
READ ENTITIES OF zbs_r_sasale IN LOCAL MODE
ENTITY SASeller
ALL FIELDS
WITH VALUE #( FOR key IN keys
( %tky = key-%tky ) )
RESULT DATA(result_set).
LOOP AT result_set INTO DATA(result_record).
INSERT VALUE #( %tky = result_record-%tky
%param = CORRESPONDING #( result_record ) ) INTO TABLE result.
ENDLOOP.
Führen wir nun die Aktion im UI aus, dann wird der Datensatz nach Ausführung aktualisiert, aber nicht ausgeblendet. Das Access Control wird daher nicht noch einmal zusätzlich durchlaufen. Hier könntest du auch die Eingabe der Felder anpassen, damit im Nachgang nicht weitere Änderungen vorgenommen werden.
Vollständiges Beispiel
Das vollständige Beispiel findest du in GitHub im entsprechenden Paket für die Sales App. Die Änderungen aus diesem Artikel findest du in diesem Commit und kannst damit die Änderungen, plus die Zusatzinformationen, nachvollziehen.
Fazit
Die Draft Query hilft uns bei der Steuerung der Sichtbarkeit des Drafts. Nicht jedes Item soll im Draft vielleicht sichtbar sein, vor allem wenn es auch bereits im Anzeigemodus ausgeblendet wurde. Über die beiden Zugriffswege kann die Sichtbarkeit auch zusätzlich noch unterschiedlich ausgesteuert werden.
Quelle:
SAP Help - Draft Query




