ADBC-API | Z-Klasse | Dynamic Native SQL Empfehlung

  • Montag, 13. Juni 2016 14:11
Artikel bewerten
(0 Stimmen)

Open SQL ist in SAP ABAP integriert und ermöglicht einen Datenbank unabhängigen Datenzugriff. In diesem Beitrag möchte ich eine andere Variante des Datenbankzugriffs vorstellen. Native SQL mit ADBC

Exkursion:

 "Static Native SQL 
EXEC SQL. 
  COMMIT WORK 
ENDEXEC. 

"Dynamic Native SQL 
NEW cl_sql_statement( )->execute_update( `COMMIT WORK` ).

Meine Intension:

Warum nicht eine Standard Klasse entwickeln, dich ich in unterschiedlichen Anwendungen verwenden kann. Aus diesem Grund ist diese Klasse enstanden.

Ich benötigte eine SAP Anwendung die Daten aus einer externen Datenbank lädt. Ein wesentlicher Bestandteil dieser Anwendung war die Selektionsmaske.

In dieser Selektionsmaske war unter anderen die Anforderung, für bestimmte Parameter eine Wertehilfe zur Verfügung zu stellen. Da diese Daten jedoch nicht in SAP gespeichert sind, musste ich einen Weg finden, wie ich auf einfache Weise mir die Daten von der externen Datenbank laden kann. Die Lösung war Dynamic Native SQL.

 

Beispiel Implementierung:

Im sourceode sieht das ganze auszugsweise dann so aus.

@Start Of Selection

*-- Field: Projektstatus{
AT SELECTION-SCREEN ON VALUE-REQUEST FOR so_900_2-low.
  TRY .
      so_900_2-low = go_gui_manager->get_f4_helper( )->get_table_projectstatus( ).
    CATCH zcx_zso5_salv INTO gr_exception.
  ENDTRY.

@F4-Helper Class

 METHOD get_table_projectstatus.
    DATA: lt_dynpread TYPE STANDARD TABLE OF dynpread,
          ls_dynpread LIKE LINE OF lt_dynpread,
          lv_stepl    TYPE systepl.
    FIELD-SYMBOLS: <fs_sel_row_tab> TYPE STANDARD TABLE.
    FIELD-SYMBOLS: <fs_sel_row_line> TYPE any.
*== create
    TRY .
        DATA(oref_f4) = NEW zcl_zso5_salv(
            iv_generic_func   = abap_true
            iv_as_popup       = abap_true
            iv_standard_ucomm = abap_true
            iv_itab           = me->mo_process_manager->get_dto_apqp_ausw( )->get_tab_projekt_status( )
            ).
        oref_f4->create_my_alv( ).
*== set selection mode: single
        oref_f4->my_salv_table->get_selections( )->set_selection_mode(
            value = if_salv_c_selection_mode=>single
        ).
*== hide columns
        oref_f4->set_my_column_visible(
          EXPORTING
            iv_columnname  = 'PROJECTSTATUS_MLID'    " [str] ALV-Control: Feldname internes Tabellenfeld
            iv_non_visible = abap_true    " [bool] visible | not visible
        ).
        oref_f4->set_my_column_visible(
          EXPORTING
            iv_columnname  = 'LANGID'    " [str] ALV-Control: Feldname internes Tabellenfeld
            iv_non_visible = abap_true    " [bool] visible | not visible
        ).
        oref_f4->set_my_column_visible(
          EXPORTING
            iv_columnname  = 'COMMENTS'    " [str] ALV-Control: Feldname internes Tabellenfeld
            iv_non_visible = abap_true    " [bool] visible | not visible
        ).
        oref_f4->set_my_column_visible(
          EXPORTING
            iv_columnname  = 'MANDANT'    " [str] ALV-Control: Feldname internes Tabellenfeld
            iv_non_visible = abap_true    " [bool] visible | not visible
        ).
*== disable the change button
        oref_f4->display_change_button( abap_false ).
*== display
        oref_f4->display_my_alv( ).
*== get selected row{
        oref_f4->get_my_selected_row(
          RECEIVING
            rv_seltab        = DATA(sel_row)    " [ref] selected rows @ SALV Object
          EXCEPTIONS
            no_rows_selected = 1
            no_data          = 2
            no_checkbox      = 3
            OTHERS           = 4
        ).
        IF sy-subrc = 0.
*== get sy-stepl from current POV{ | this function is necessary
          CALL FUNCTION 'DYNP_GET_STEPL'
            IMPORTING
              povstepl = lv_stepl.
*== get sy-stepl from current POV}
          ASSIGN sel_row->* TO <fs_sel_row_tab>.
          ASSIGN rv_proj_status TO FIELD-SYMBOL(<fs_so_900_2_low>).
          LOOP AT <fs_sel_row_tab> ASSIGNING <fs_sel_row_line>.
            ASSIGN COMPONENT 'PROJECTSTATUSID' OF STRUCTURE <fs_sel_row_line>
            TO FIELD-SYMBOL(<fs_sel_row_field>).
            <fs_so_900_2_low> = <fs_sel_row_field>.
            ls_dynpread-fieldname = 'SO_900_2-LOW'.
            ls_dynpread-fieldvalue = <fs_sel_row_field>.
            ls_dynpread-stepl = lv_stepl.
            APPEND ls_dynpread TO lt_dynpread.
          ENDLOOP.
*== update the screen field values { | this function is necessary
          CALL FUNCTION 'DYNP_VALUES_UPDATE'
            EXPORTING
              dyname     = sy-repid
              dynumb     = sy-dynnr
            TABLES
              dynpfields = lt_dynpread.
*== Update the screen field values}
        ENDIF.
*== get selected row}
*== clear object
        CLEAR oref_f4.
      CATCH cx_salv_msg.
    ENDTRY.
  ENDMETHOD.

@DTO Class

  METHOD get_tab_projekt_status.
    rt_projekt_status = me->mt_projekt_status.
  ENDMETHOD.

Bei der Instanzierung der Helper Klasse

 *== Helper Classes
    me->mo_f4_helper = zcl_zqq6_apqp_ausw_f4_helper=>get_instance( ).

wird folgende Methode ebenfalls ausgeführt.

 METHOD create_table_projectstatus.
*== `SELECT PROJECTSTATUSID,NAME FROM CASQIT.PROJECT_STATUS_ML WHERE LANGID ='7'` ##no_text.
    DATA: lv_connection_name TYPE dbcon-con_name.
    DATA: lt_cols   TYPE adbc_column_tab.
*== set the current database{
    CASE sy-sysid(1).
      WHEN 'D' OR 'Q'.
        lv_connection_name = 'DB1' ##no_text.
      WHEN 'R'.
        lv_connection_name = 'DB2' ##no_text.
    ENDCASE.
*create a connection object representing the default connection.
    DATA(oref_adbc) = NEW ycl_so5_adbc(
        iv_db_connection_name = lv_connection_name
    ).
    lt_cols = VALUE #( ( 'PROJECTSTATUSID' ) ( 'NAME' ) ).
    DATA(lt_projstatus) = me->mo_apqp_ausw_dto->get_tab_projekt_status( ).
    oref_adbc->select_into_table(
      EXPORTING
        iv_sql_query    = `SELECT * FROM ihrTabellenname WHERE LANGID ='7'` ##no_text " [str] sql query
*        it_column_tab   = lt_cols " [tab of column names
      CHANGING
        ct_output_table = lt_projstatus " [tab] of output table
    ).
*== save tab @ my dto object
    SORT lt_projstatus BY name ASCENDING AS TEXT.
    me->mo_apqp_ausw_dto->set_tab_projekt_status( lt_projstatus ).
  ENDMETHOD.

Dies ist nur ein Beispiel für die Verwendung meiner Klasse. Ich selbst habe noch viele weitere Verwendungen meiner Klasse in dieser Anwendung. Dieses Beispiel soll bzw. kann euch nur zeigen, wie man meine Klasse verwenden kann/könnte. Kommen wir nun zu der Beschreibung der 2 Methoden dieser Klasse.

Methoden der Klasse:

1. CONSTRUCTOR

Parameter:

IV_DB_CONNECTION_NAME - Logischer Name einer Datenbankverbindung

Wird bei der Objekterzeugung verwendet. Mit dem Paremter wird eine aktive Verbindung zu der entsprechenden Datenbank aufgebaut. Das Objekt selbst besitzt also in ihrer gesamten Laufzeit eine aktive Verbindung zu der gewählten Datenbank.

2. SELECT_INTO_TABLE

Parameter:

IV_SQL_QUERY - [str] sql query
IV_DB_NAME - [str] name of the database
IT_COLUMN_TAB - [tab of column names
IR_SCREEN_FIELDS - [ref] of my screen fields
CT_OUTPUT_TABLE - [tab] of output table

Mit dieser Methode ist es möglich, über ein SQL Statement Daten aus der Datenbank zu selektieren und in eine interne Tabelle temporär zu speichern. Besonderheit in dieser Klasse ist die Möglichkeit ein vordefiniertes SQL Statement an die Methode zu übergeben oder aber mit Hilfe der COLUMN_TAB sowie der SCREEN_FIELDS ein SQL Statement dynamisch zu generieren. Weitere Informationen über die Logik könnt ihr ab Zeile 87 im sourcecode entnehmen.

YCL_SO5_ADBC (sourcecode)

 

Fazit:

Ich selbst bin froh diese Klasse entwickelt zu haben, denn sie erleichtert mir die Arbeit mit externen Datenbank zu arbeiten. Wie ihr euch mit Sicherheit denken könnt, steckt noch sehr viel Potenzial in dieser Klasse. Sobald ich mehr Zeit habe, werde ich auch diese Klasse um weitere Methoden/Funktionen erweitern. Ein Beispiel wäre zum Beispiel das Abspeichern. Was denkt ihr? Habt ihr vielleicht einen Verbesserungsvorschlag? Lasst es mich einfach wissen. Gerne könnt ihr hierfür die Kommentarfunktion nutzen.

In diesem Sinne

Blogging is a conversation, not a code.

Letzte Änderung am %PM, %15. %554 %2016 %12:%Jun
Kommentare einblenden

Copyright © 2017 ABAP-Workbench.de