This is a test message to test the length of the message box.
Login
ABAP Deep Dive Corresponding
Erstellt von Software-Heroes

ABAP Deep Dive - CORRESPONDING

In diesem Artikel einmal etwas mehr über das neue Corresponding Statement und wie man es im Detail einsetzen kann. Dabei schauen wir einmal auf die zusätzlichen Features.

Werbung

Bereits in einem älteren Artikel sind wir bereits auf das neue Statement eingegangen und haben einige Vorzüge davon erklärt. In diesem Artikel wollen wir uns einige neue Faceten anschauen und wie du sie optimal nutzen kannst. Uns ist auch aufgefallen, dass durch Entwickler meist nicht das volle Potential der Statements genutzt wird, um Coding einzusparen. In diesem Zusammenhang wollen wir uns einige Neuerungen und Besonderheiten anschauen.

 

Einleitung

Der neue CORRESPONDING ist ein Konstruktor-Ausdruck, dass heißt er erzeugt ein neues Element aus seinem Quellobjekt. Hierbei kannst du es dir so vorstellen, dass dazu ein neues Element fürs Ziel erzeugt wird, dabei leer ist und dann die Zuweisung nach den entsprechenden Regeln durchgeführt wird. Die Werte werden dabei kopiert und das Quellobjekt nicht verändert. Dies hat den schönen Vorteil, dass du dir zum Beispiel innerhalb eines Loops das Clear sparst, wenn die Loop-Struktur einer neuen Struktur für die Verarbeitung zugewiesen wird.

 

Vorbereitung

Für die nachfolgenden Beispiele definieren wir uns separate Strukturen und Tabellentypen, die wir nutzen möchten. Dabei gibt es immer eine Quellstruktur und eine Zielstruktur, bei der einige Feldnamen gleich sind und einige unterschiedlich. Im gesamten Beispiel unten im Artikel bekommst du das gesamte Beispiel.

TYPES:
  td_text   TYPE c LENGTH 25,
  td_number TYPE i,
  td_long   TYPE string,

  BEGIN OF ts_source,
    text1    TYPE td_text,
    text3    TYPE td_text,
    num1     TYPE td_number,
    longtext TYPE td_long,
  END OF ts_source,
  tt_source TYPE STANDARD TABLE OF ts_source WITH EMPTY KEY,

  BEGIN OF ts_target,
    ident    TYPE td_number,
    num      TYPE td_number,
    longtext TYPE td_long,
    text1    TYPE td_text,
    text2    TYPE td_text,
  END OF ts_target,
  tt_target     TYPE STANDARD TABLE OF ts_target WITH EMPTY KEY,
  tt_target_key TYPE SORTED TABLE OF ts_target WITH UNIQUE KEY ident,

  BEGIN OF ts_source_nested,
    field1 TYPE td_text,
    sub    TYPE ts_source,
  END OF ts_source_nested,

  BEGIN OF ts_target_nested,
    field TYPE td_text,
    sub   TYPE ts_target,
  END OF ts_target_nested.

 

Ein einfacher MOVE der Strukturen sieht daher wie folgt aus, dabei werden nur die gleichnamigen Komponenten verschoben, wodurch die Zielstruktur relativ leer bleibt:

DATA(ls_source) = fill_structure( ).
DATA(ls_target) = CORRESPONDING ts_target( ls_source ).

io_out->write( |Simple move:| ).
io_out->write( ls_target ).

 

MAPPING

Beim Einsatz eines Mappings können nicht namensgleiche Komponenten mit verschoben werden, dabei wir Quell- und Zielfeld im Mapping angegeben. Zur besseren Hilfe steht dir in Eclipse auch der Content Assist (STRG + LEERTASTE) zur Verfügung:

DATA(ls_source) = fill_structure( ).
DATA(ls_target) = CORRESPONDING ts_target( ls_source MAPPING text2 = text3 num = num1 ).

io_out->write( |Move with mapping:| ).
io_out->write( ls_target ).

 

Die Ausgabe sieht nun wie folgt aus, die übrigen und vorhandenen Felder wurden nun erfolgreich gemappt und der Zielstruktur zugewiesen:

 

EXCEPT

Manchmal sollen Felder nach der Zuweisung gelöscht werden, dann wenn es um die Weiterverarbeitung geht oder die Felder leer sein müssen, da sie nicht mehr benötigt werden oder zu Problemen führen können. In der Vergangenheit hat man dazu, nach der Zuweisung, einen Clear der entsprechenden Felder durchgeführt. Dies kann man sich mit dem Zusatz EXCEPT sparen, da dieser dafür sorgt, dass die Felder nicht in die Zielstruktur überführt werden:

DATA(ls_source) = fill_structure( ).
DATA(ls_target) = CORRESPONDING ts_target( ls_source MAPPING text2 = text3 num = num1 EXCEPT longtext ).

io_out->write( |Move without longtext:| ).
io_out->write( ls_target ).

 

In dem Beispiel oben, haben wir das gleiche Mapping wie vorher durchgeführt, dieses Mal wollen wir allerdings den Langtext nicht mit kopieren. Die Zielstruktur sieht nun wie folgt aus:

 

DISCARDING DUPLICATES

Es gibt Fälle, bei der eine Standardtabelle in eine sortierte Tabelle mit Schlüssel überführt werden soll. Hier muss man sich aber sicher sein, dass der Schlüssel in der Quelltabelle nur einmal vorhanden ist, da es ansonsten zu einer Ausnahme kommt und die Verarbeitung abbricht. In der Vergangenheit konntest du dies mit mehreren Statements tun (Sortierung der Tabelle und entfernen der Duplikate). In diesem Beispiel befüllen wir die Tabelle unsortiert und mit einem Duplikat und verwenden bei der Zuweisung DISCARDING DUPLICATES, damit werden die Duplikate entfernt und es kommt zu keiner Ausnahme:

DATA(lt_source) = VALUE tt_source(
  ( num1 = 14 text1 = 'Bread' )
  ( num1 = 3 text1 = 'Butter' )
  ( num1 = 7 text1 = 'Jam' )
  ( num1 = 14 text1 = 'Salt' )
  ( num1 = 11 text1 = 'Egg' )
  ( num1 = 19 text1 = 'Coffee' )
).

DATA(lt_target) = CORRESPONDING tt_target_key( lt_source DISCARDING DUPLICATES MAPPING ident = num1 ).

io_out->write( |Move table with key:| ).
io_out->write( lt_target ).

 

Das Nummernfeld mappen wir entsprechend auf den Schlüssel und entfernen die Duplikate. Der jeweils erste Eintrag wird dabei in die Zieltabelle übernommen und das Ergebnis sieht wie folgt aus:

 

Nested Mapping

Wie sieht es eigentlich mit verschachtelten Strukturen aus? Hierbei geht es um Strukturen, die auf Feldebene eine weitere Struktur oder Tabelle abbilden und somit mehrere Ebenen haben. Hier kannst du ebenfalls das Mapping anwenden, wie wir es bereits oben getan haben. Wenn du dann die tiefe Struktur ansprechen möchtest, musst du das Element in eine Klammer packen und dort ein eigenes Mapping durchführen:

DATA(ls_source) = VALUE ts_source_nested(
  field1 = 'Sub structure'
  sub = fill_structure( )
).

DATA(ls_target) = CORRESPONDING ts_target_nested( ls_source
  MAPPING field = field1
  ( sub = sub MAPPING text2 = text3 num = num1 )
).

io_out->write( |Nested move:| ).
io_out->write( ls_target-field ).
io_out->write( ls_target-sub ).

 

In dem Beispiel haben wir das Hauptfeld gemappt und für die tiefe Struktur ein weiteres Mapping geöffnet. Die Ausgabe muss in zwei Schritten erfolgen, da die Ausgabemethode keine tiefen Strukturen unterstützt:

 

Gesamtes Beispiel

Wie immer findest du hier das vollständige Beispiel in Form einer ausführbaren ABAP Klasse. Die einzelnen Beispiele sind in einzelne Methoden ausgelagert worden, um für bessere Lesbarkeit zu sorgen:

CLASS zcl_bs_demo_corresponding_deep DEFINITION PUBLIC FINAL CREATE PUBLIC.
  PUBLIC SECTION.
    INTERFACES if_oo_adt_classrun.

    TYPES:
      td_text   TYPE c LENGTH 25,
      td_number TYPE i,
      td_long   TYPE string,

      BEGIN OF ts_source,
        text1    TYPE td_text,
        text3    TYPE td_text,
        num1     TYPE td_number,
        longtext TYPE td_long,
      END OF ts_source,
      tt_source TYPE STANDARD TABLE OF ts_source WITH EMPTY KEY,

      BEGIN OF ts_target,
        ident    TYPE td_number,
        num      TYPE td_number,
        longtext TYPE td_long,
        text1    TYPE td_text,
        text2    TYPE td_text,
      END OF ts_target,
      tt_target     TYPE STANDARD TABLE OF ts_target WITH EMPTY KEY,
      tt_target_key TYPE SORTED TABLE OF ts_target WITH UNIQUE KEY ident,

      BEGIN OF ts_source_nested,
        field1 TYPE td_text,
        sub    TYPE ts_source,
      END OF ts_source_nested,

      BEGIN OF ts_target_nested,
        field TYPE td_text,
        sub   TYPE ts_target,
      END OF ts_target_nested.

  PROTECTED SECTION.
  PRIVATE SECTION.
    METHODS:
      fill_structure
        RETURNING VALUE(rs_source) TYPE ts_source,

      move_simple_structure
        IMPORTING
          io_out TYPE REF TO if_oo_adt_classrun_out,

      move_with_mapping
        IMPORTING
          io_out TYPE REF TO if_oo_adt_classrun_out,

      move_without_fields
        IMPORTING
          io_out TYPE REF TO if_oo_adt_classrun_out,

      move_duplicate_tables
        IMPORTING
          io_out TYPE REF TO if_oo_adt_classrun_out,

      move_nested_structure
        IMPORTING
          io_out TYPE REF TO if_oo_adt_classrun_out.
ENDCLASS.


CLASS zcl_bs_demo_corresponding_deep IMPLEMENTATION.
  METHOD if_oo_adt_classrun~main.
    move_simple_structure( out ).
    move_with_mapping( out ).
    move_without_fields( out ).
    move_duplicate_tables( out ).
    move_nested_structure( out ).
  ENDMETHOD.


  METHOD fill_structure.
    rs_source  = VALUE ts_source(
      text1 = 'Some value'
      text3 = 'New values'
      num1 = 12
      longtext = `This is a very long ABAP string in a structure field`
    ).
  ENDMETHOD.


  METHOD move_simple_structure.
    DATA(ls_source) = fill_structure( ).

    DATA(ls_target) = CORRESPONDING ts_target( ls_source ).

    io_out->write( |Simple move:| ).
    io_out->write( ls_target ).
  ENDMETHOD.


  METHOD move_with_mapping.
    DATA(ls_source) = fill_structure( ).

    DATA(ls_target) = CORRESPONDING ts_target( ls_source MAPPING text2 = text3 num = num1 ).

    io_out->write( |Move with mapping:| ).
    io_out->write( ls_target ).
  ENDMETHOD.


  METHOD move_without_fields.
    DATA(ls_source) = fill_structure( ).

    DATA(ls_target) = CORRESPONDING ts_target( ls_source MAPPING text2 = text3 num = num1 EXCEPT longtext ).

    io_out->write( |Move without longtext:| ).
    io_out->write( ls_target ).
  ENDMETHOD.


  METHOD move_duplicate_tables.
    DATA(lt_source) = VALUE tt_source(
      ( num1 = 14 text1 = 'Bread' )
      ( num1 = 3 text1 = 'Butter' )
      ( num1 = 7 text1 = 'Jam' )
      ( num1 = 14 text1 = 'Salt' )
      ( num1 = 11 text1 = 'Egg' )
      ( num1 = 19 text1 = 'Coffee' )
    ).

    DATA(lt_target) = CORRESPONDING tt_target_key( lt_source DISCARDING DUPLICATES MAPPING ident = num1 ).

    io_out->write( |Move table with key:| ).
    io_out->write( lt_target ).
  ENDMETHOD.


  METHOD move_nested_structure.
    DATA(ls_source) = VALUE ts_source_nested(
      field1 = 'Sub structure'
      sub = fill_structure( )
    ).

    DATA(ls_target) = CORRESPONDING ts_target_nested( ls_source
      MAPPING field = field1
      ( sub = sub MAPPING text2 = text3 num = num1 )
    ).

    io_out->write( |Nested move:| ).
    io_out->write( ls_target-field ).
    io_out->write( ls_target-sub ).
  ENDMETHOD.
ENDCLASS.

 

Fazit

Das neue Statement ist mächtiger als man zu glauben scheint. Zusammen mit dem älteren Artikel zum Thema CORRESPONDING erhältst du den vollen Überblick über das neue Statement und wie du es sinnvoll nutzen kannst.

 


Enthaltene Themen:
Deep DiveCorrespondingModernes ABAP
Kommentare (0)

ABAP Deep Dive - VALUE

Kategorie - ABAP

In diesem Artikel wollen wir uns noch einmal das Value Statement in allen Ausprägungen anschauen und wie du es in deiner täglichen Arbeit nutzen kannst.

11.11.2022

ABAP - Corresponding und Value

Kategorie - ABAP

Die beiden Ausdrücke fokussieren vor allem auf das Erstellen von Strukturen und verschieben von Dateninhalten im Zusammenhang von Tabellen. Beide wollen wir dir heute zeigen und welche Befehle sie ablösen.

07.12.2018

ABAP - Common Table Expression (CTE)

Kategorie - ABAP

In diesem Artikel wollen wir uns einmal den allgemeinen Tabellenausdruck WITH anschauen und wie du ihn im Alltag nutzen kannst.

28.10.2022

ABAP - Step

Kategorie - ABAP

Heute einmal ein neuer Zusatz für die Schleifen und wie du ihn verwenden kannst. Mit Step hast du die Möglichkeiten Schritte in einer Schleife zu überspringen.

02.09.2022

ABAP - SELECT FROM @itab

Kategorie - ABAP

Über eine interne Tabelle selektieren war früher mit vielen Zeilen Code realisiert, heute funktioniert es auch praktisch über den Select.

20.01.2022