Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
Andre_Fischer
Product and Topic Expert
Product and Topic Expert
374

Introduction

Recently we got a customer influence request with the ask to release the RAP transport API’s so that the same can be used in RAP business objects that use the strict mode 2.

An example of such a RAP business object is a Business Configuration Maintenance Object that has been generated using the ABAP Repository Object Generator.

When you just change the behavior definition and the behavior projection such that they use the strict mode 2 instead of the basic strict mode 

 

 

 

managed with additional save implementation in class ZBP_I_HOLIDAYCAL2_S unique;
//strict;
strict ( 2 );
with draft;

 

 

 

and

 

 

 

projection implementation in class ZBP_C_HOLIDAYCAL2_S unique;
//strict;
strict ( 2 );
use draft;

 

 

 

we would get the following dump when trying to save the data to a customizing request:

Statement "EXEC SQL COMMIT" is not allowed with this status.

Since making the existing RAP transport API's compatible with the strict mode 2 is probably a task that cannot be achieved at all together with colleagues I thought about possible workarounds.

We came up with the idea to wrap the calls of the transport API's which cause the trouble using the background processing framework.

This can be achieved by some small changes to the save_modified method of the behavior implementation class and by providing a wrapper class that implements the interfaces of the background processing framework.

So let’s get started.

Generate a business configuration maintenance object

For this blog post I have used the tables listed at the end of the blog post and the generator for business configuration maintenance objects which is described in this tutorial

Create Business Configuration Maintenance Object | SAP Tutorials

In addition one has to create appropriate authorizations for the CDS view that will be generated (here ZI_HolidayCal2)  rah

Andre_Fischer_1-1724260514670.png

 

 

 

Changes in the behavior implementation class

In the behavior implementation class we have to adapt the save_modified( ) method and we have to add types definitions in the global behavior class which can be used by our wrapper class.

Local saver class

In the save_modified method we comment out the call of the local class lhc_rap_tdat_cts which contains the call of the RAP transport API.

Instead we are using a class called zcl_record_changes_via_bgpf which implements the interfaces if_serializable_object, if_bgmc_operation and if_bgmc_op_single_tx_uncontr.

The latter allows us to call API’s that may contain commit work statements which would cause a dump when being called directly in the behavior implementation. Instead this class acts as wrapper and and starts the call of the transport API asynchronously in a new process.

 

 

CLASS lsc_zi_holidaycal2_s DEFINITION FINAL INHERITING FROM cl_abap_behavior_saver.
  PROTECTED SECTION.
    METHODS:
      save_modified REDEFINITION,
      cleanup_finalize REDEFINITION.
ENDCLASS.

CLASS lsc_zi_holidaycal2_s IMPLEMENTATION.
  METHOD save_modified.

    READ TABLE update-HolidayCal2All INDEX 1 INTO DATA(all).
    IF all-TransportRequestID IS NOT INITIAL.

      "start new implementation

      DATA bgpf_operation TYPE REF TO zcl_record_changes_via_bgpf .

      bgpf_operation = NEW zcl_record_changes_via_bgpf(
        i_transport_request = all-TransportRequestID
        i_create            = create
        i_update            = update
        i_delete            = delete
      ).
      TRY.
          DATA(background_process) = cl_bgmc_process_factory=>get_default(  )->create(  ).
          background_process->set_operation_tx_uncontrolled( bgpf_operation ).
          background_process->set_name( CONV #( all-TransportRequestID ) ).
          background_process->save_for_execution(  ).
        CATCH cx_bgmc.
          "handle exception
          ASSERT 1 = 2.
      ENDTRY.

      "end new implementation

*      lhc_rap_tdat_cts=>get( )->record_changes(
*                                  transport_request = all-TransportRequestID
*                                  create            = REF #( create )
*                                  update            = REF #( update )
*                                  delete            = REF #( delete ) ).

    ENDIF.
  ENDMETHOD.
  METHOD cleanup_finalize ##NEEDED.
  ENDMETHOD.
ENDCLASS.

 

 

 

Global class

In the global class we add three type statements so that we can reuse the same in the constructor of our wrapper class.

 

 

CLASS zbp_i_holidaycal2_s DEFINITION
  PUBLIC
  ABSTRACT
  FINAL
  FOR BEHAVIOR OF zi_holidaycal2_s .

  PUBLIC SECTION.

    TYPES : t_create TYPE REQUEST FOR CHANGE zi_holidaycal2_s,
            t_update TYPE REQUEST FOR CHANGE zi_holidaycal2_s,
            t_delete type request for delete zi_holidaycal2_s .
  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.

CLASS zbp_i_holidaycal2_s IMPLEMENTATION.
ENDCLASS.

 

 

 

Wrapper class zcl_record_changes_via_bgpf

The wrapper class contains fairly generic coding. The constructor takes the three complex structures which contains the data which shall be written to our customizing request.

Since the class will be serialized by the background processing framework I have made sure that the constructor does not take the references but the actual values of the tables that are passed by the behavior implementation.

 

 

 

CLASS zcl_record_changes_via_bgpf DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.

    INTERFACES if_serializable_object .
    INTERFACES if_bgmc_operation .
    INTERFACES if_bgmc_op_single_tx_uncontr .




    METHODS constructor
      IMPORTING i_transport_request TYPE sxco_transport
                i_create            TYPE zbp_i_holidaycal2_s=>t_create
                i_update            TYPE zbp_i_holidaycal2_s=>t_update
                i_delete            TYPE zbp_i_holidaycal2_s=>t_delete.


  PROTECTED SECTION.
  PRIVATE SECTION.

    DATA : transport_request TYPE sxco_transport,
           create            TYPE zbp_i_holidaycal2_s=>t_create,
           update            TYPE zbp_i_holidaycal2_s=>t_update,
           delete            TYPE zbp_i_holidaycal2_s=>t_delete.
ENDCLASS.



CLASS zcl_record_changes_via_bgpf IMPLEMENTATION.

  METHOD constructor.
    create = i_create.
    update = i_update.
    delete = i_delete.
    transport_request = i_transport_request.
  ENDMETHOD.

  METHOD if_bgmc_op_single_tx_uncontr~execute.

    lhc_rap_tdat_cts=>get( )->record_changes(
                                transport_request = transport_request
                                create            = REF #( create )
                                update            = REF #( update )
                                delete            = REF #( delete ) ).

  ENDMETHOD.

ENDCLASS.

 

 

Local class LHC_RAP_TDAT_CTS

Our wrapper class zcl_record_changes_via_bgpf uses the same code as the one that we have commented out in the save_modified( ) method of the generated behavior implementation.

We have thus to create a local class LHC_RAP_TDAT_CTS in our global class zcl_record_changes_via_bgpf as well.

 

 

CLASS LHC_RAP_TDAT_CTS DEFINITION FINAL.
  PUBLIC SECTION.
    CLASS-METHODS:
      GET
        RETURNING
          VALUE(RESULT) TYPE REF TO IF_MBC_CP_RAP_TDAT_CTS.

ENDCLASS.

CLASS LHC_RAP_TDAT_CTS IMPLEMENTATION.
  METHOD GET.
    result = mbc_cp_api=>rap_tdat_cts( tdat_name = 'ZHOLIDAYCAL2'
                                       table_entity_relations = VALUE #(
                                         ( entity = 'HolidayCal2' table = 'ZBC_FCAL_HOLI' )
                                         ( entity = 'HolidayCal2Text' table = 'ZBC_FCAL_HOLI_T' )
                                       ) ) ##NO_TEXT.
  ENDMETHOD.
ENDCLASS.

 

 

Result

When we now start the business configuration app and enter data and save the same,

Andre_Fischer_0-1724257931605.png

this data can be written to customizing request that we have to create beforehand.

Andre_Fischer_1-1724257960598.png

Andre_Fischer_2-1724257969603.png

 

Tables used

For this demo I used the following tables and generated a business configuration maintenance object based on these two tables

zbc_fcal_holi

 

@EndUserText.label : 'Holiday Cal2'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #C
@AbapCatalog.dataMaintenance : #ALLOWED
define table zbc_fcal_holi {

  key client            : mandt not null;
  key holiday_id        : zdmo_fcal_holiday_id not null;
  month_of_holiday      : fdt_month;
  day_of_holiday        : fdt_day_of_month;
  configdeprecationcode : config_deprecation_code;
  last_changed_at       : abp_lastchange_tstmpl;
  local_last_changed_at : abp_locinst_lastchange_tstmpl;

}

 

zbc_fcal_holi_t

 

@EndUserText.label : 'Holiday Cal2 Text Table'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #C
@AbapCatalog.dataMaintenance : #ALLOWED
define table zbc_fcal_holi_t {

  key client            : mandt not null;
  @AbapCatalog.textLanguage
  key lang              : abap.lang not null;
  @AbapCatalog.foreignKey.keyType : #TEXT_KEY
  @AbapCatalog.foreignKey.screenCheck : false
  key holiday_id        : zdmo_fcal_holiday_id not null
    with foreign key [0..*,1] zbc_fcal_holi
      where client = zbc_fcal_holi_t.client
        and holiday_id = zbc_fcal_holi_t.holiday_id;
  fcal_description      : sxco_ao_short_description;
  local_last_changed_at : abp_locinst_lastchange_tstmpl;

}