ABAP in der Praxis - Typkonvertierung
Wie würdest du diese Typkonvertierung in ABAP durchführen? Ein Beispiel aus der Praxis und ein Lösungsvorschlag.
Inhaltsverzeichnis
In diesem Artikel werden wir einem Beispiel aus der Praxis nachgehen und wie man das Problem recht einfach mit Modern ABAP umsetzen kann.
Einleitung
Die Herausforderung besteht darin eine Selektionstabelle vom Typ RSSELECT in eine Selektion vom Gateway zu konvertieren. Dabei gibt es vor allem eine größere Strukturveränderung. Die Ausgangstabelle ist flach und die Zieltabelle strukturiert die Select-Options bereit in einer tiefen Struktur vor.
Auf der linken Seite des Bildes ist unsere Ausgangsstruktur, Ziel ist die Tabelle auf der rechten Seite.
Vorbereitung
Als Vorbereitung legen wir uns eine ausführbare Klasse im System an, definieren die Typen die wir benötigen und generieren einige Beispieldaten, die wir zum Testen verwenden können.
CLASS zcl_bs_demo_practice_typ_conv DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PRIVATE SECTION.
TYPES ts_rsselect TYPE rsselect.
TYPES tt_rsselect TYPE STANDARD TABLE OF ts_rsselect WITH EMPTY KEY.
TYPES tt_result TYPE /iwbep/t_mgw_select_option.
METHODS convert_type
IMPORTING it_rsselect TYPE tt_rsselect
RETURNING VALUE(rt_result) TYPE tt_result.
ENDCLASS.
CLASS zcl_bs_demo_practice_typ_conv IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA(lt_source) = VALUE tt_rsselect(
( fieldnm = 'IDENT' sign = 'I' option = 'EQ' low = 'A10' )
( fieldnm = 'DATE' sign = 'I' option = 'BT' low = '20240501' high = '20240520' )
( fieldnm = 'IDENT' sign = 'I' option = 'BT' low = 'A11' high = 'A15' )
( fieldnm = 'NAME' sign = 'E' option = 'EQ' low = 'Meier' )
( fieldnm = 'NAME' sign = 'E' option = 'EQ' low = 'Scholz' )
( fieldnm = 'TIME' sign = 'I' option = 'GE' low = '190000' ) ).
DATA(lt_result) = convert_type( lt_source ).
ENDMETHOD.
METHOD convert_type.
ENDMETHOD.
ENDCLASS.
Aufgabe
Deine Aufgabe wäre nun die Implementierung der Methode CONVERT_TYPE. Die Methode bekommt über IT_RSSELECT die befüllte Quelltabelle geliefert und RT_RESULT muss befüllt werden.
Hinweis: Im nächsten Abschnitt werden wir auf die Lösung eingehen, wenn du die Aufgabe erst einmal selbstständig machen möchtest, solltest du hier pausieren.
Lösung
Wie können wir dieses Problem nun mit Modern ABAP lösen? Dazu verwenden wir im ersten Schritt eine Schleife, um über die übergebenen Daten zu iterieren. Hier können wir mit einer Inline-Deklaration arbeiten, um uns die Definition der Variable zu sparen.
LOOP AT it_rsselect INTO DATA(ls_rsselect).
ENDLOOP.
Im nächsten Schritt müssen wir in der Tabelle eine neue Zeile anlegen, wenn diese noch nicht existiert, ansonsten würden wir die Zeile lesen, um sie im letzten Schritt zu erweitern. Wir könnten beide Fälle separat abbilden, je nach Komplexität würden wir aber viel redundantes Coding erzeugen. Daher versuchen wir im ersten Schritt die bestehende Zeile aus der Tabelle zu lesen und weisen das Ergebnis einer neuen Referenz zu. Damit hätten wir einen Zeiger, mit dem wir Änderungen direkt in RT_RESULT durchführen können. Wir der Eintrag nicht gefunden, weil er Neu ist, dann wird die Ausnahme CX_SY_ITAB_LINE_NOT_FOUND ausgelöst. In diesem Fall würden wir per INSERT nur unseren Schlüssel einfügen und zusätzlich den Pointer der Referenz LR_MAPPED. In beiden Fällen verweist LR_MAPPED nun auf die Zeile, die wir bearbeiten wollen.
TRY.
DATA(lr_mapped) = REF #( rt_result[ property = ls_rsselect-fieldnm ] ).
CATCH cx_sy_itab_line_not_found.
INSERT VALUE #( property = ls_rsselect-fieldnm ) INTO TABLE rt_result REFERENCE INTO lr_mapped.
ENDTRY.
Zum Abschluss können wir die restlichen Daten an die Tabelle mit den SELECT_OPTIONS hängen. Dazu führen wir Inline ein Mapping der Daten per CORRESPONDING durch und hängen das Ergebnis an unsere Referenz. Da wir hier nicht mit einer Kopie der Tabellenzeile arbeiten, sondern mit einer Referenz, sparen wir uns den MODIFY der RESULT Tabelle.
INSERT CORRESPONDING #( ls_rsselect ) INTO TABLE lr_mapped->select_options.
Komplettes Beispiel
In diesem Abschnitt findest du die finale Klasse mit der entwickelten Methode und du kannst das Beispiel mit deiner Implementierung abgleichen.
CLASS zcl_bs_demo_practice_typ_conv DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PRIVATE SECTION.
TYPES ts_rsselect TYPE rsselect.
TYPES tt_rsselect TYPE STANDARD TABLE OF ts_rsselect WITH EMPTY KEY.
TYPES tt_result TYPE /iwbep/t_mgw_select_option.
METHODS convert_type
IMPORTING it_rsselect TYPE tt_rsselect
RETURNING VALUE(rt_result) TYPE tt_result.
ENDCLASS.
CLASS zcl_bs_demo_practice_typ_conv IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA(lt_source) = VALUE tt_rsselect(
( fieldnm = 'IDENT' sign = 'I' option = 'EQ' low = 'A10' )
( fieldnm = 'DATE' sign = 'I' option = 'BT' low = '20240501' high = '20240520' )
( fieldnm = 'IDENT' sign = 'I' option = 'BT' low = 'A11' high = 'A15' )
( fieldnm = 'NAME' sign = 'E' option = 'EQ' low = 'Meier' )
( fieldnm = 'NAME' sign = 'E' option = 'EQ' low = 'Scholz' )
( fieldnm = 'TIME' sign = 'I' option = 'GE' low = '190000' ) ).
DATA(lt_result) = convert_type( lt_source ).
ENDMETHOD.
METHOD convert_type.
LOOP AT it_rsselect INTO DATA(ls_rsselect).
TRY.
DATA(lr_mapped) = REF #( rt_result[ property = ls_rsselect-fieldnm ] ).
CATCH cx_sy_itab_line_not_found.
INSERT VALUE #( property = ls_rsselect-fieldnm ) INTO TABLE rt_result REFERENCE INTO lr_mapped.
ENDTRY.
INSERT CORRESPONDING #( ls_rsselect ) INTO TABLE lr_mapped->select_options.
ENDLOOP.
ENDMETHOD.
ENDCLASS.
Fazit
Viele Wege führen nach Rom und das würde auch für die Lösung der Aufgabe gelten. Mit Modern ABAP ist die Lösung mit wenig Aufwand umsetzbar. Wenn du eine ganz andere Lösung hast, poste den Inhalt der Methode CONVERT_TYPE als Alternative in die Kommentare.