Web Dynpro - schlankere Context-Zugriffe programmieren

Posten Sie hier Tutorials & Cookbooks.
1 Beitrag • Seite 1 von 1
1 Beitrag Seite 1 von 1

Web Dynpro - schlankere Context-Zugriffe programmieren

Beitrag von Lukas Sanders (ForumUser / 78 / 9 / 42 ) »
Die Datenbindung im Web Dynpro über Context-Knoten verursacht, insbesondere wenn man sich den Code über den Code Wizard generieren lässt, manchmal unnötig viele Codezeilen und führt daher schnell zu unübersichtlichen Methoden.

Mit ein paar einfachen Schritten kann man die Menge an Code jedoch deutlich reduzieren.

Urzustand nach Code Wizard

Im Beispiel lesen wir eine Struktur mit Suchfeldern aus. Lassen wir einmal die Kommentare und die Fehlerbehandlung beiseite, führt dies zu 3 Datendeklarationen und 3 Methodenaufrufen.

Code: Alles auswählen.

    
    DATA lo_nd_sflight_search TYPE REF TO if_wd_context_node.
    DATA lo_el_sflight_search TYPE REF TO if_wd_context_element.
    DATA ls_sflight_search TYPE wd_this->element_sflight_search.

    lo_nd_sflight_search = wd_context->get_child_node( name = wd_this->wdctx_sflight_search ).

    lo_el_sflight_search = lo_nd_sflight_search->get_element( ).

    lo_el_sflight_search->get_static_attributes(
      IMPORTING
        static_attributes = ls_sflight_search ).
So kann man zwar nachvollziehen, was genau in welcher Reihenfolge passiert, allerdings dürfte dies in den wenigsten Fällen wirklich relevant sein und die vielen Codezeilen dürften bei komplexeren Methoden eher stören.

Stufe 1 - Kontext-Element sparen

In dem vom Code Wizard erzeugten Code werden Referenzen für den Kontext-Knoten (lo_el_...) und das Kontext-Element (lo_el_...) erzeugt. Ist das wirklich notwendig?

In den meisten Fällen nicht. Laut Dokumentation zum Interface IF_WD_CONTEXT_ELEMENT sind die meisten Methoden - so auch die zum Abruf der Daten - auch im Interface IF_WD_CONTEXT_NODE vorhanden und sie funktionieren auch genau so. Wir brauchen also die Referenz auf das Element in den meisten Fällen gar nicht.

Wir können die Methode zur Datenbeschaffung (auch zum Schreiben der Daten) also direkt an der Knoten-Referenz aufrufen und die Element-Referenz weglassen. Hierdurch sparen wir uns 2 Zeilen.

Code: Alles auswählen.

    DATA: lo_nd_sflight_search TYPE REF TO if_wd_context_node,
          ls_sflight_search TYPE wd_this->element_sflight_search.
    
    lo_nd_sflight_search = wd_context->get_child_node( name = wd_this->wdctx_sflight_search ).

    lo_nd_sflight_search->get_static_attributes(
      IMPORTING
        static_attributes = ls_sflight_search ).
Eine Besonderheit gibt es allerdings: Werden die Methoden direkt an der Knoten-Referenz aufgerufen, wird die Lead-Selection angesprochen. Falls dies unerwünscht ist, kann aber auch der Index des Elements direkt über einen weiteren Parameter angegeben werden.

Bei Tabellen wird übrigens bereits durch den Code Wizard das Element "eingespart" - Hier ist die Lead-Selection auch nicht relevant.

Code: Alles auswählen.

  DATA lo_nd_sflight TYPE REF TO if_wd_context_node.
  DATA lt_sflight TYPE wd_this->elements_sflight.

  lo_nd_sflight = wd_context->get_child_node( name = wd_this->wdctx_sflight ).

  lo_nd_sflight->get_static_attributes_table( IMPORTING table = lt_sflight ).
Stufe 2 - Verketteter Methodenaufruf

Weitere Codezeilen können wir sparen, wenn wir die Möglichkeiten des ABAP OO voll ausnutzen.

Die Methode GET_CHILD_NODE der Referenz WD_CONTEXT gibt eine Referenz auf den Kontext-Knoten als Returning-Parameter zurück (funktionale Methode). Wir haben diese Referenz in den obigen Beispielen zuerst lokal zwischengespeichert und später genutzt, um den Knoten anzusprechen.

Die OO-Syntax erlaubt es allerdings auch, das Ergebnis einer solchen funktionalen Methode genau so zu verwenden und anzusprechen wie eine lokale Variable oder Referenz.

Wir können also auf die lokale Referenz verzichten, indem wir die Lese- bzw. Schreibmethoden direkt am Ergebnis der Methode GET_CHILD_NODE aufrufen. Damit sparen wir uns zwei weitere Zeilen.

Das Lesen und Schreiben passt somit auch in eine einzige sehr lange Zeile.

Code: Alles auswählen.

wd_context->get_child_node( name = wd_this->wdctx_sflight_search )->get_static_attributes( IMPORTING static_attributes = ls_sflight_search ).
Der Nachteil ist sicherlich, dass dieser Code recht weit vom "selbsterklärenden" ABAP entfernt ist und je nach Eingewöhnung erst einmal "abschreckend" wirken könnte.

Auch kann sich eine lokale Referenz lohnen, wenn man mehrmals auf den Contextknoten zugreifen möchte.

Stufe 3 - Generische Setter- und Getter-Methoden

Manche Menschen bauen sich in Hilfsklassen eigene Setter- und Getter-Methoden, um besonders in komplexen Projekten Knoten zu füllen und zu lesen. Ein Beispiel ist in diesem Blog beschrieben:

https://blogs.sap.com/2014/01/16/custom ... npro-abap/

Von diesen recht komplexen Lösungen bin ich auch noch immer nicht ganz überzeugt. Schließlich bringt SAP ja Standardfunktionen mit, wieso also hier etwas Eigenes bauen? Zielführend dürfte so etwas wohl wirklich nur in sehr großen und komplexen Projekten sein oder dann, wenn man solche Methoden häufig wiederverwenden kann.

Die Grundidee finde ich allerdings gar nicht verkehrt. Durch eine selbstständige Methode, die einfach Knotennamen und Daten entgegennimmt und die WD-spezifischen, technischen Schritte auslagert, könnte man den Methodencode auf das Wesentliche reduzieren.

Hat man viele Lese- und Schreiboperationen auf verschiedene Kontext-Knoten in seinem Projekt, kann dies tatsächlich Zeit sparen - vor allem, wenn man den Quelltext 'mal eben kopieren kann.

Man könnte also das Beste aus beiden Welten verbinden und generische Setter-/Getter-Methoden bauen, die ausschließlich Standardmittel nutzen und sich noch im WD-Konzept bewegen.

Grundlagen

Tatsächlich ist die Vorgehensweise bei Context-Zugriffen relativ einfach und folgt immer dem gleichen Muster:

Erst wird eine Referenz auf den Knoten geholt (GET_CHILD_NODE), dann wird über diese Objektreferenz die Methode zum Lesen oder Setzen der Daten aufgerufen (GET_STATIC_ATTRIBUTES / SET_STATIC_ATTRIBUTES).

Der Ergebnisparameter der Lese- und Schreibmethoden ist generisch, die Methoden zum Lesen und Setzen der Daten heißen auch stets gleich. Die Referenz auf den WD-Kontext, die noch benötigt wird, ist ohnehin verfügbar.

Im Grunde muss man also für eine solche generische Methode nur wissen, wie man eine Referenz auf den richtigen Kontext-Knoten bekommt, also wie man den folgenden Methodenaufruf richtig steuert:

Code: Alles auswählen.

lo_nd_sflight_search = wd_context->get_child_node( name = wd_this->wdctx_sflight_search ).
WD_THIS->WDCTX_SFLIGHT_SEARCH ist hier nichts anderes als eine Konstante, welche den Namen des Knotens in Großbuchstaben enthält - hier 'SFLIGHT_SEARCH'. Mehr als den Namen braucht es also gar nicht, um einen Knoten anzusprechen.

Man sollte hier allerdings überlegen, ob man nicht lieber die Konstante statt eines Literals verwendet, auch wenn sie weniger gut lesbar ist - gemäß Clean-Code-Regeln sollte man dies unbedingt tun. Man bekommt so einen Verwendungsnachweis geschenkt und bei Namensänderungen gibt es keine Probleme.

Einfache generische Methode

In meinem Beispiel gehe ich davon aus, dass alle "wichtigen" Kontext-Knoten am Component-Controller definiert und auf die einzelnen Views gemappt sind, ich also vom Component-Controller aus zentral auf die einzelnen Knoten zugreifen kann. Sonst würde dieser Ansatz nicht funktionieren.

Wenn man so vorgeht, kann man die generische Methode problemlos am Component-Controller definieren und über die Referenz auf den Controller (WD_COMP_CONTROLLER) aus Views und Windows aufrufen.

Dafür definiert man eine einfache Methode (z.B. SET_NODE) mit einem Import-Parameter (IV_NODE) für den Knotennamen vom Typen String und einen Import-Parameter für die Daten (IR_DATA) eines generischen Typen.

Die Methode an sich ist ein einfacher Dreizeiler. Wir deklarieren eine Referenz, füllen diese über die Methode WD_CONTEXT->GET_CHILD_NODE (wobei wir den Import-Parameter Knotennamen übergeben) und rufen dann die Set-Methode auf (wobei wir die übergebene Datenstruktur weiterreichen).

Code: Alles auswählen.

METHOD set_node .

  DATA: lo_node TYPE REF TO if_wd_context_node.

  lo_node = wd_context->get_child_node( name = iv_node ).

  lo_node->set_static_attributes(
    EXPORTING
      static_attributes = ir_data ).

ENDMETHOD.
Die Lesemethode wird analog definiert, nur muss dort natürlich die Datenstruktur ein Exporting- oder Changing-Parameter sein.

Code: Alles auswählen.

method GET_NODE .
  
  DATA: lo_node TYPE REF TO if_wd_context_node.

  lo_node = wd_context->get_child_node( name = iv_node ).

  lo_node->get_static_attributes(
    IMPORTING
      static_attributes = cr_data ).
  
endmethod.
In der aufrufenden Methode (am Controller, Window oder View) brauchen wir nun nur noch eine passende (Struktur-) Variable...

Code: Alles auswählen.

  DATA  ls_sflight_search    TYPE wd_this->element_sflight_search.
... und können dann direkt am Controller die Methode aufrufen.

Code: Alles auswählen.

wd_comp_controller->get_node(
  EXPORTING
    iv_node = wd_this->wdctx_sflight_search
  CHANGING
    cr_data = ls_sflight_search ). 
So hat man zwar einen leichten Overhead, aber gleichzeitig eine noch gut lesbare Kurzform geschaffen.

Einschränkungen und Erweiterungsmöglichkeiten

Diese sehr einfache Methode reicht für mich in den meisten Fällen aus, kann jedoch in der Form nur ganze, einzeilige Knoten als Struktur lesen und setzen, keine Attribute und auch keine Tabellen.

Natürlich darf man auch eine ordentliche Fehlerbehandlung nicht vergessen!

Hier kann aber natürlich noch viel gebastelt werden - von einem zusätzlichen Importparameter, über welchen Tabellen- und Einzelwertoperationen angesteuert werden können, bis hin zu einer Typerkennung über die RTTI-Services ist vieles denkbar.

Auch kann man natürlich noch den Quelltext der Setter-/Getter-Methode "eindampfen" und bei der Getter-Methode die Daten als Returning-Parameter auswerfen, sodass die Deklaration in der aufrufenden Methode ggf. entfallen kann und so weiter...

Ich hoffe aber, hiermit bereits einige Ansätze geliefert zu haben, Web-Dynpro-Methoden übersichtlicher zu gestalten und einiges an redundanter Arbeit zu sparen.

Folgende Benutzer bedankten sich beim Autor Lukas Sanders für den Beitrag:
ewx


gesponsert
Stellenangebote auf ABAPforum.com schalten
kostenfrei für Ausbildungsberufe und Werksstudenten


Seite 1 von 1

Vergleichbare Themen

1
Antw.
8790
Views
Context Binding Error
von Rantanplan78 » 21.02.2017 11:47 • Verfasst in Web-Dynpro, BSP + BHTML
0
Antw.
2804
Views
Watchpoint auf Webdynpro Context
von donossi » 18.01.2012 12:07 • Verfasst in ABAP® für Anfänger
1
Antw.
1925
Views
Context im Debugger auslesen
von donossi » 11.05.2011 12:02 • Verfasst in ABAP® für Anfänger
7
Antw.
4660
Views
ALV-OO, Umleitung Hotspot auf Context Menu
von Alexander D. » 27.09.2012 09:58 • Verfasst in ABAP Objects®
0
Antw.
2564
Views
Abap Webdynpro - Context Change -Lo
von leon » 04.08.2011 18:51 • Verfasst in Dialogprogrammierung

Über diesen Beitrag

Lukas Sanders

Unterstütze die Community und teile den Beitrag für mehr Leser und Austausch

Newsletter Anmeldung

Keine Beiträge verpassen! Wöchentlich versenden wir lesenwerte Beiträge aus unserer Community.
Die letzte Ausgabe findest du hier.
Details zum Versandverfahren und zu Ihren Widerrufsmöglichkeiten findest du in unserer Datenschutzerklärung.