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.
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
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.
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.
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.
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.
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.
When we now start the business configuration app and enter data and save the same,
this data can be written to customizing request that we have to create beforehand.
For this demo I used the following tables and generated a business configuration maintenance object based on these two tables
@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;
}
@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;
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
26 | |
13 | |
12 | |
11 | |
9 | |
9 | |
7 | |
5 | |
5 | |
5 |