Technical Articles
Using long string in function imports
Motivation
Recently I got a question in SCN where a SCN user had problems with sending long strings using a function import.
So I created a SEGW project in both the latest stack as well as in 740 (the latest SP though) to check whether I would be able to reproduce the issue.
I wasn’t able to do so but wanted to share in detail how it worked for me.
I will work on publishing this and other code on Github but for the time being I just post screen shots and source code
SEGW Project
I created a project ZAF_SAMPLE_001 with an entity type SalesOrderDescription and an EntitySet SalesOrderDescription as follows:
soid is of type Edm.String , length 10
description is of type Edm.String, length 1000
Both field names were chosen automatically since the entity type is not bound to a DDIC structure.
Then I created a function import SetDescription with two parameters Salesorder (Edm.String with a length of 10) and Description (Edm.String with a length 1000).
The ABAP Field Names ZAF_SAMPLE_001_DESCRIPTION and ZAF_SAMPLE_001_SALESORDER are NOT existing DDIC types but the names were just chosen randomly when creating the function import parameters.
Table
The data was stored in a simple table whose fields are using the ABAP internal types CHAR(30) and CHAR(1000).
@EndUserText.label : 'long descriptions'
@AbapCatalog.enhancementCategory : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #LIMITED
define table zaf_sample_001 {
key client : abap.clnt not null;
key soid : abap.char(10) not null;
description : abap.char(1000);
}
Result
When posting the following URI I got a response where all characters (more than 400 are being returned)
/sap/opu/odata/SAP/ZAF_SAMPLE_001_SRV/SetDescription?Salesorder='29'&Description='100 characters: '0123456789'0123456789'0123456789'0123456789'0123456789'0123456789'0123456789'0123456789'0123456789'0123456789'0123456789 200 characters: '0123456789'0123456789'0123456789'0123456789'0123456789'0123456789'0123456789'0123456789'0123456789'0123456789'0123456789 300 characters: '0123456789'0123456789'0123456789'0123456789'0123456789'0123456789'0123456789'0123456789'0123456789'0123456789'0123456789 400 characters: '0123456789'0123456789'0123456789'0123456789'0123456789'0123456789'0123456789'0123456789'0123456789'0123456789'0123456789'
DPC_EXT class (740)
Here is the code of the DPC_EXT class for 740 where no inline declaration of variables is allowed an no “@” must be used to mark parameters in SQL statements as host variables.
class ZCL_ZAF_SAMPLE_001_DPC_EXT definition
public
inheriting from ZCL_ZAF_SAMPLE_001_DPC
create public .
PUBLIC SECTION.
METHODS /iwbep/if_mgw_appl_srv_runtime~execute_action
REDEFINITION .
PROTECTED SECTION.
METHODS salesorderdescri_get_entity REDEFINITION.
METHODS salesorderdescri_get_entityset REDEFINITION.
private section.
ENDCLASS.
CLASS ZCL_ZAF_SAMPLE_001_DPC_EXT IMPLEMENTATION.
METHOD salesorderdescri_get_entityset.
DATA: lv_osql_where_clause TYPE string,
lv_top TYPE i,
lv_skip TYPE i,
lv_max_index TYPE i,
n TYPE i.
*- get number of records requested
lv_top = io_tech_request_context->get_top( ).
*- get number of lines that should be skipped
lv_skip = io_tech_request_context->get_skip( ).
*- value for maxrows must only be calculated if the request also contains a $top
IF lv_top IS NOT INITIAL.
lv_max_index = lv_top + lv_skip.
ENDIF.
lv_osql_where_clause = io_tech_request_context->get_osql_where_clause( ).
SELECT * FROM zaf_sample_001
INTO CORRESPONDING FIELDS OF TABLE et_entityset
UP TO lv_max_index ROWS
WHERE (lv_osql_where_clause).
*- skipping entries specified by $skip
IF lv_skip IS NOT INITIAL.
DELETE et_entityset TO lv_skip.
ENDIF.
*- Inlinecount - get the total numbers of entries that fit to the where clause
IF io_tech_request_context->has_inlinecount( ) = abap_true.
SELECT COUNT(*) FROM zaf_sample_001 WHERE (lv_osql_where_clause) .
es_response_context-inlinecount = sy-dbcnt.
ELSE.
CLEAR es_response_context-inlinecount.
ENDIF.
ENDMETHOD.
METHOD salesorderdescri_get_entity.
DATA: lt_keys TYPE /iwbep/t_mgw_tech_pairs,
ls_key TYPE /iwbep/s_mgw_tech_pair,
ls_bp_key TYPE zcl_zaf_sample_001_mpc=>ts_salesorderdescription-soid,
ls_headerdata TYPE zcl_zaf_sample_001_mpc=>ts_salesorderdescription.
CALL METHOD io_tech_request_context->get_converted_keys
IMPORTING
es_key_values = ls_headerdata.
ls_bp_key = ls_headerdata-soid.
SELECT SINGLE *
INTO CORRESPONDING FIELDS OF er_entity
FROM zaf_sample_001
WHERE soid = ls_headerdata-soid.
ENDMETHOD.
METHOD /iwbep/if_mgw_appl_srv_runtime~execute_action.
DATA: ls_message TYPE scx_t100key.
TYPES: BEGIN OF lty_import_parameter,
ZAF_SAMPLE_001_SALESORDER TYPE zaf_sample_001-soid,
ZAF_SAMPLE_001_DESCRIPTION TYPE zaf_sample_001-description,
END OF lty_import_parameter.
DATA: ls_parameter_values TYPE lty_import_parameter,
lv_function_import_name TYPE /iwbep/mgw_tech_name.
DATA ls_sales_description TYPE zaf_sample_001. " zcl_zaf_sample_001_mpc=>ts_salesorderdescription.
DATA lt_sales_description TYPE STANDARD TABLE OF zaf_sample_001. "zcl_zaf_sample_001_mpc=>tt_salesorderdescription.
lv_function_import_name = io_tech_request_context->get_function_import_name( ).
io_tech_request_context->get_converted_parameters(
IMPORTING
es_parameter_values = ls_parameter_values ).
CASE lv_function_import_name.
WHEN 'SetDescription'.
ls_sales_description-description = ls_parameter_values-ZAF_SAMPLE_001_description.
ls_sales_description-soid = ls_parameter_values-ZAF_SAMPLE_001_salesorder.
APPEND ls_sales_description TO lt_sales_description.
*
INSERT zaf_sample_001 FROM TABLE lt_sales_description.
" INSERT zaf_sample_001 FROM @ls_sales_description.
" add check whether salesorder exist or not
IF sy-subrc <> 0.
" implement suitable error handling here
ls_message-msgid = 'SY'.
ls_message-msgno = '002'.
CONCATENATE 'Update for ' ls_parameter_values-ZAF_SAMPLE_001_SalesOrder ' failed' INTO ls_message-attr1.
RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception
EXPORTING
textid = ls_message.
* ELSE.
* ls_snwd_lock-node_key = ls_so-node_key.
ENDIF.
data ls_entity type zcl_zaf_sample_001_mpc=>ts_salesorderdescription.
SELECT SINGLE * FROM zaf_sample_001 INTO CORRESPONDING FIELDS OF ls_entity WHERE soid = ls_parameter_values-ZAF_SAMPLE_001_salesorder.
IF ls_entity IS INITIAL.
ls_message-msgid = 'SY'.
ls_message-msgno = '002'.
ls_message-attr1 = 'sales order not found'.
RAISE EXCEPTION TYPE /iwbep/cx_mgw_busi_exception
EXPORTING
textid = ls_message.
ENDIF.
copy_data_to_ref( EXPORTING
is_data = ls_entity CHANGING
cr_data = er_data
).
ENDCASE.
ENDMETHOD.
ENDCLASS.
MPC code
Extract from the definition part of the MPC class
class ZCL_ZAF_SAMPLE_001_MPC definition
public
inheriting from /IWBEP/CL_MGW_PUSH_ABS_MODEL
create public .
public section.
types:
begin of TS_SETDESCRIPTION,
ZAF_SAMPLE_001_DESCRIPTION type C length 1000,
ZAF_SAMPLE_001_SALESORDER type C length 10,
end of TS_SETDESCRIPTION .
DEFINE_ACTIONS
method DEFINE_ACTIONS.
*&---------------------------------------------------------------------*
*& Generated code for the MODEL PROVIDER BASE CLASS &*
*& &*
*& !!!NEVER MODIFY THIS CLASS. IN CASE YOU WANT TO CHANGE THE MODEL &*
*& DO THIS IN THE MODEL PROVIDER SUBCLASS!!! &*
*& &*
*&---------------------------------------------------------------------*
data:
lo_action type ref to /iwbep/if_mgw_odata_action, "#EC NEEDED
lo_parameter type ref to /iwbep/if_mgw_odata_parameter. "#EC NEEDED
***********************************************************************************************************************************
* ACTION - SetDescription
***********************************************************************************************************************************
lo_action = model->create_action( 'SetDescription' ). "#EC NOTEXT
*Set return entity type
lo_action->set_return_entity_type( 'SalesOrderDescription' ). "#EC NOTEXT
*Set HTTP method GET or POST
lo_action->set_http_method( 'POST' ). "#EC NOTEXT
*Set the action for entity
lo_action->set_action_for( 'SalesOrderDescription' ). "#EC NOTEXT
* Set return type multiplicity
lo_action->set_return_multiplicity( '1' ). "#EC NOTEXT
***********************************************************************************************************************************
* Parameters
***********************************************************************************************************************************
lo_parameter = lo_action->create_input_parameter( iv_parameter_name = 'Description' iv_abap_fieldname = 'ZAF_SAMPLE_001_DESCRIPTION' ). "#EC NOTEXT
lo_parameter->/iwbep/if_mgw_odata_property~set_type_edm_string( ).
lo_parameter->set_maxlength( iv_max_length = 1000 ). "#EC NOTEXT
lo_parameter = lo_action->create_input_parameter( iv_parameter_name = 'Salesorder' iv_abap_fieldname = 'ZAF_SAMPLE_001_SALESORDER' ). "#EC NOTEXT
lo_parameter->/iwbep/if_mgw_odata_property~set_type_edm_string( ).
lo_parameter->set_maxlength( iv_max_length = 10 ). "#EC NOTEXT
lo_action->bind_input_structure( iv_structure_name = 'ZCL_ZAF_SAMPLE_001_MPC=>TS_SETDESCRIPTION' ). "#EC NOTEXT
endmethod.
Hi Andre,
Thank you for nice blog.
How about SAP Gateway license for SAP Business Suite named user license, need additional license or not?
Best regards,
Andy
Since this question is not related to this blog can you please post it in the Q&A section.
Sorry, I already posted my question in the Q&A section. I hope you can help me, thank you.
No problem. Gregor Wolf already answered this and I confirmed it.
Hello,
The trouble I see with long strings, is that function import parameters are passed in the query string of the POST request, and query strings could have a limit imposed by the server (does Netweaver impose a limit?) or the client browser.
So ideally, I would like to pass the long string in the body of the request. Is that possible?
BTW I'm also currently using RAP and not gateway (no DPC_EXT or MPC_EXT).
Thank you for documenting this - I think I also saw your comment about using a length of 0 to indicate usage of STRING.
The issue I ran into that was immensely frustrating was having to rename the ABAP field in order to really regenerate the definitions/declarations. Editing a data model entity type definition doesn't seem to invoke the same behavior as when you generate/create it from scratch.
For example, my field was called ShipComments and even though I changed it to a length of 0, I still received the blessed "violates facet information" error.
After I renamed the ABAP field name from SHIP_COMMENTS to SHIP_COMMENTS_STRING, I guess it forced something to be regenerated.
Anyway - this was the best article on the subject, so I thought I would share this in case it helps someone..