
RAP - Tree View (Löschverhalten)
In diesem Artikel schauen wir uns das Verhalten beim Löschen von Knoten im Tree View mit RAP an. Dabei gibt es einige interessante Punkte zu beachten.
Inhaltsverzeichnis
Im letzten Artikel hatten wir uns die Anzeige als Tree View angeschaut, dabei gab es noch eine Frage von Philip Davy zum Löschverhalten des Baums. In diesem Artikel schauen wir uns das Verhalten einmal im Detail an und versuchen eine Lösung zu finden.
Einleitung
Aktuell haben wir auf unserer ListPage (Einstiegsseite) einen Baum implementiert, der unsere Daten als Baum anzeigt. Über die Standardfunktionalitäten im RAP können wir neue Einträge hinzufügen. Markieren wir Einträge in der Liste, können wir auch Einträge entfernen. Dazu schauen wir uns das Löschverhalten in diesem Artikel einmal im Detail an.
Löschen
In diesem Kapitel schauen wir uns das Löschverhalten innerhalb des Baums an. Dazu gehen wir verschiedene Szenarien durch und prüfen gegen die Datenbank.
Einzeln
In diesem Fall wollen wir einen einzelnen Knoten ohne Unterknoten entfernen. Dazu markieren wir den Eintrag im Baum und löschen über den "Delete" Button.
Prüfen wir nun die Daten auf der Datenbank, wurde der Eintrag "P0023" entfernt.
Mehrere (eine Ebene)
Im nächsten Beispiel markieren wir mehrere Einträge auf einer Ebene. Dabei ist wieder kein Wurzelknoten davon betroffen und löschen die beiden Einträge.
Prüfen wir die Tabelle, dann wurden die beiden Knoten von der Datenbank entfernt.
Einzeln (Oberknoten)
In diesem Beispiel löschen wir einen Oberknoten, der noch einen Unterknoten hat (P0021). Wurde das Löschen durchgeführt, sind beide Knoten nicht mehr in der Hierarchie sichtbar.
Prüfen wir die Datenbank, wurde unser Oberknoten gelöscht, der Unterknoten P0021 ist aber noch vorhanden (wurde nicht markiert).
Mehrere (Obernoten)
Im letzten Fall selektieren wir einen Oberknoten und einige Unterknoten. Die Unterknoten befinden sich in diesem Fall unter unserem Oberknoten und führen die Löschung durch.
Prüfen wir die Datenbank, dann stellen wir fest, dass nur der Oberknoten gelöscht wurde. Die markierten Unterknoten befinden sich weiterhin in den Daten.
Annahmen
Wenn du nun die App aufrufst, werden keine Daten mehr angezeigt, es befinden sich allerdings die nicht gelöschten Einträge noch auf der Datenbank. Dazu können wir nun die Punkte von oben zusammenfassen und eine Annahme treffen.
- Das Löschen im Baum ohne Auswahl einer Oberknotens funktioniert wie im normalen List Report und die Einträge werden aus der Anzeige und von der Datenbank entfernt.
- Beim Löschen eines Oberknoten, wird dieser entfernt und die Unterelemente nicht mehr angezeigt, diese werden allerdings nicht mit gelöscht, auch wenn wir sie eigentlich zum Löschen markiert hatten.
Schauen wir uns den zweiten Punkt einmal im Browser an, dann sehen wir, wenn wir mehrere Einträge und die Wurzel selektiert haben, dass nur der Oberknoten im Batch-Request gesendet wird. Die Markierung der anderen Einträge wird also ignoriert.
Mittlerweile gibt es auf dem ABAP Environment und der Public Cloud auch den editierbaren Baum und damit einige mehr Funktionen. Dazu kann in der Assoziation der Zusatz "with cascading delete" angegeben werden. Dies funktioniert allerdings nicht in unserem Fall, da unser Baum auf Root-Ebene definiert ist und wir daher nur die Warnung erhalten, dass das aktuell nicht unterstützt wird. Falls du es doch implementierst, wirst du bei der Ausführung der Löschung einen Dump erhalten, der auf die Implementierung des Sperrobjekts verweist.
Lösungsvorschlag
Wie können wir nun eine allgemeine Lösung für das aktuelle Verhalten implementieren? Wir gehen also davon aus, wenn wir den Oberknoten löschen, dass wir auch die Unterknoten löschen und im zweiten Szenario die Knoten neu zuordnen.
Additional Save
Zu diesem Zweck implementieren wir ein eigenes Verhalten beim Speichern der Daten. Dazu definieren wir in der Verhaltensdefinition den Zusatz "WITH ADDITIONAL SAVE" und lassen uns die Implementierung in der Verhaltensimplementierung anlegen (STRG + 1).
CLASS lsc_zbs_r_dmotreeteam DEFINITION INHERITING FROM cl_abap_behavior_saver.
PROTECTED SECTION.
METHODS
save_modified REDEFINITION.
ENDCLASS.
CLASS lsc_zbs_r_dmotreeteam IMPLEMENTATION.
METHOD save_modified.
LOOP AT delete-team INTO DATA(member).
ENDLOOP.
ENDMETHOD.
ENDCLASS.
Damit haben wir die Möglichkeit ein zusätzliches Verhalten beim Speichern der Daten zu implementieren. Da uns in diesem Moment die zu löschenden Datensätze interessieren, reicht uns der Input Parameter DELETE.
Ermittlung
Im zweiten Schritt benötigen beide Varianten die Möglichkeit die darunterliegenden Knoten zu lesen. Dazu definieren wir uns eine rekursive Methode, die uns die Möglichkeit gibt, den unterliegenden Baum zu lesen.
TYPES node TYPE ZBS_I_DMOTreeTeamHR.
TYPES nodes TYPE SORTED TABLE OF node WITH UNIQUE KEY UserId.
METHODS get_subnodes
IMPORTING user_id TYPE ZBS_I_DMOTreeTeamHR-UserId
recursive TYPE abap_boolean
RETURNING VALUE(result) TYPE nodes.
Die Methode liest die Hierarchie und sucht alle Knoten unter unserem aktuell betroffenen Knoten. Übergeben wir unser Kennzeichen für Rekursiv, dann werden auch alle Unterknoten gesucht, um so die komplette Hierarchie zu haben.
METHOD get_subnodes.
SELECT FROM ZBS_I_DMOTreeTeamHR
FIELDS *
WHERE TeamLeader = @user_id
INTO TABLE @DATA(subnodes).
LOOP AT subnodes INTO DATA(subnode).
INSERT subnode INTO TABLE result.
IF recursive = abap_true.
INSERT LINES OF get_subnodes( user_id = subnode-UserId
recursive = recursive ) INTO TABLE result.
ENDIF.
ENDLOOP.
ENDMETHOD.
Löschen
Möchten wir nun alle Unterknoten löschen, müssen wir zuerst einmal alle Unterknoten der Hierarchie ableiten. Im Anschluss löschen wir die Daten direkt von der Datenbank oder über einen entsprechenden DAO, je nach Implementierung.
DATA(subnodes) = get_subnodes( user_id = user_id
recursive = abap_true ).
LOOP AT subnodes INTO DATA(subnode).
DELETE FROM zbs_dmo_team WHERE user_id = @subnode-UserId.
ENDLOOP.
Löschen wir nun den Oberknoten "P0025", dann erwarten wir, dass alle Unterknoten mit aus der Datenbank entfernt werden.
Bei der Prüfung der Inhalte der Datenbank, befinden sich nur noch die anderen Knoten dort.
Zuweisen
Eine Alternative ist die Zuweisung der nicht gelöschten Daten. In diesem Fall benötigen wir nur die direkten Unterknoten und weisen diese einem neuen Knoten zu. In diesem Fall verwenden wir den Knoten "P0000" den wir zuvor noch anlegen müssen.
DATA(subnodes) = get_subnodes( user_id = user_id
recursive = abap_false ).
LOOP AT subnodes INTO DATA(subnode).
UPDATE zbs_dmo_team SET team_leader = 'P0000' WHERE user_id = @subnode-UserId.
ENDLOOP.
Dazu legen wir den Knoten für "Not Assigned" an und löschen den Knoten "P0020". Damit sollten die Einträge dann verschoben werden.
In der Datenbank wurde der Knoten "P0020" gelöscht, alle anderen Knoten sind noch verfügbar.
Schauen wir uns zum Abschluss noch die Anzeige in unserer Elements Preview an, dann wurden die Knoten sauber verschoben und sind unter dem neuen Oberknoten verfügbar.
Vollständiges Beispiel
Alle Änderungen an der App findest du wie immer im GitHub Repository. Über den Commit findest du die vorgenommenen Veränderungen im RAP Objekt.
Fazit
Im Moment scheint der Baum noch etwas abweichend von den Erwartungen zu funktionieren, hier solltest du deinen Kollegen klar machen, was sie erwarten können und was nicht funktioniert, damit es nicht zu Fehlern im Handling kommt. Grundsätzlich hast du nun aber auch zwei Möglichkeiten, das Verhalten entsprechend zu beeinflussen.
Weitere Informationen:
SAP Help - Treeviews: Architecture Overview
SAP Help - Defining the Behavior for the Hierarchy