2.6 Using Batch Technique to Submit Large Data-set via oData Service
Foreword
The following technique uses a technique known as Batch posting from the front-end web application. To facilitate this, it is necessary to implement CHANGESET processing in a SAP oData service.
CHANGESET processing allows multiple records of data to be passed to SAP. Each record can be temporarily stored in an internal table (UPDATE_ENTITY is called for each record). When all the data has been passed, the method CHANGESET_END can be used to process the full internal table of data.
FAB Application
Take FAB_DEMO_EXCEL_DROP as an example
Implement oData Service
In this example, use FAB’s Entity Set Designer to build a service. (Note it is also possible to use other methods to build the service, such as via transaction SEGW)
Define the Entity “Person” and the Entity Set “People”
Create and activate the Data Provider service and Model Service using the “Model/Service” section of the Entity Set Designer.
When complete, ensure to add the resulting service model to the FAB application. Here we used Identifier “person”
Implement Changeset Processing (Back-End oData Service)
Navigate to the Data Provider Class
From the class editor, expand the “Methods” node and redefine the following methods.
/IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_BEGIN
/IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_END
/IWBEP/IF_MGW_APPL_SRV_RUNTIME~GET_ENTITY
/IWBEP/IF_MGW_APPL_SRV_RUNTIME~UPDATE_ENTITY
CHANGESET_BEGIN
First create an internal table as an attribute of the data provider class.
private section.
types:
begin of T_PERSON,
id type AD_PERSNUM,
firstName type AD_NAMEFIR,
lastName type AD_NAMELAS,
end of t_person .
types:
t_person_tt TYPE STANDARD TABLE OF t_person .
data GT_PERSON type T_PERSON_TT .
data GV_ENTITY_TYPE type STRING .
Also create an attribute GV_ENTITY_TYPE
Add the following lines of code to the CHANGESET_BEGIN method
method /IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_BEGIN.
DATA: ls_operation_info LIKE LINE OF it_operation_info.
LOOP AT it_operation_info INTO ls_operation_info.
gv_entity_type = ls_operation_info-entity_type.
ENDLOOP.
REFRESH: gt_person.
EXIT.
endmethod.
This method will be called when the batch starts. Here you can identify the Entity that is being updated and refresh the internal table.
UPDATE_ENTITY
This method is called for each record passed in the batch. Use this method to append each record to the global internal table
method /IWBEP/IF_MGW_APPL_SRV_RUNTIME~UPDATE_ENTITY.
* implement change set
DATA: ls_person TYPE t_person.
* implement Change Set processing
IF gv_entity_type = 'Person'.
io_data_provider->read_entry_data( IMPORTING es_data = ls_person ).
APPEND ls_person TO gt_person.
ENDIF.
endmethod.
CHANGESET_END
This method is called when all the data in the batch has been passed. It will be possible to access the internal table full of data. You can do what you want with the internal table (update a table, call a BAPI, create a GOS object etc).
method /IWBEP/IF_MGW_APPL_SRV_RUNTIME~CHANGESET_END.
IF gv_entity_type = 'Person'.
"gt_person
endif.
endmethod.
Set an external break-point here to see the contents of GT_PERSON should be full.
GET_ENTITY
This method is needed to be implemented for the full changeset to function.
METHOD /iwbep/if_mgw_appl_srv_runtime~get_entity.
* This needs to be implemented for $batch updates using oData model V2
DATA: lo_request TYPE REF TO /iwbep/cl_mgw_request,
ls_request TYPE /iwbep/if_mgw_core_srv_runtime=>ty_s_mgw_request_context,
ls_key_tab LIKE LINE OF it_key_tab.
FIELD-SYMBOLS: <row> TYPE any,
<value> TYPE any.
lo_request ?= io_tech_request_context.
* need to pass something back in ER_ENTITY, even if it's not used
READ TABLE it_key_tab INTO ls_key_tab WITH KEY name = 'ID'.
IF sy-subrc = 0.
CREATE DATA er_entity TYPE t_person.
ASSIGN er_entity->* TO <row>.
ASSIGN COMPONENT 'ID' OF STRUCTURE <row> TO <value>.
<value> = ls_key_tab-value.
ENDIF.
ENDMETHOD.
* Note here we use a dereferencing operation because our ER_ENTITY is dynamic and declared as TYPE REF TO DATA. If the service was implemented via SEGW, it may be more simpler.
Implement Batch Submit (Front-End)
In the FAB app we have defined a button “Upload to SAP” which executes a Script function “uploadData()”
function uploadData(){
console.log("upload data");
var batchChanges = [];
var oModel = getModel("person");
var oData = getField("myData");
for(var i in oData){
var oRecord = oData[i];
var oPath = "/People(ID='" + oRecord.ID + "')";
var batchChange = {};
batchChange.path = oPath;
batchChange.data = oRecord;
batchChanges.push(batchChange);
}
var updateComplete = function(evt){
console.log("update complete");
oModel.detachRequestCompleted(updateComplete);
};
console.log("starting upload..");
oModel.attachRequestCompleted(null, updateComplete );
for(var j in batchChanges){
var batchChange = batchChanges[j];
oModel.update(batchChange.path, batchChange.data,{
success: function(oData, oResponse) {
},
error:function(oError){
console.log("error");
},
changeSetId:"1",
});
}
};
Note you may want to make this routine a little more sophisticated by adding a progress indicator and success message depending on your application. The function “updateComplete” is called when the update is complete.
Test
In browser, run
Use a spreadsheet file (eg “People.xlsx”), with content such as
Drop it on to the Excel Drop Target and the table should fill with the data. Then press “Upload to SAP” and set a breakpoint in the CHANGESET_END method and you should see the internal table GT_PERSON containing the data.
Also watch the Chrome console..