‎2023 Mar 28 9:03 AM
Hey there!
I tried a little bit using nested reads.
The objective is to map fields of one (internal or normal) structure to a BAPI structure with the following access:
These are the reads to perform the access:
LOOP AT components_int INTO DATA(component_int).
CLEAR field.
field-int = component_int-fieldname.
TRY.
field-bapi = components_bapi[ fieldname = component_int-fieldname ]-fieldname.
field-origin = c_origin_fields_equal.
CATCH cx_sy_itab_line_not_found.
TRY.
field-bapi = components_bapi[ fieldname = component_int-deffdname ]-fieldname.
field-origin = c_origin_default_component.
CATCH cx_sy_itab_line_not_found.
TRY.
field-bapi = components_bapi[ rollname = component_int-rollname ]-fieldname.
field-origin = c_origin_rollname_equal.
CATCH cx_sy_itab_line_not_found.
field-origin = c_origin_no_match.
ENDTRY.
ENDTRY.
ENDTRY.
APPEND field TO fields.
ENDLOOP.
But I didn't like the nested TRY-CATCH commands and tried various other versions.
One version is the following nested VALUE - DEFAULT command:
field-bapi = VALUE #( components_bapi[ fieldname = component_int-fieldname ]-fieldname
DEFAULT VALUE #( components_bapi[ fieldname = component_int-deffdname ]-fieldname
DEFAULT VALUE #( components_bapi[ rollname = component_int-rollname ]-fieldname ) ) ).
But this version has an insuffiency: The information, which access level was found will not be transported.
therefore I tried the following:
field = VALUE #( bapi = VALUE #( components_bapi[ fieldname = component_int-fieldname ]-fieldname
DEFAULT VALUE ts_field( bapi = VALUE #( components_bapi[ fieldname = component_int-deffdname ]-fieldname
DEFAULT VALUE ts_field( bapi = VALUE #( components_bapi[ rollname = component_int-rollname ]-fieldname
DEFAULT VALUE ts_field( bapi = space origin = c_origin_no_match )
) origin = c_origin_rollname_equal )
) origin = c_origin_default_component )
) origin = c_origin_fields_equal ) .
But this version does not work. The origin fields equal will always be used.
And I do not find out, why... 😞
Here is the complete code on github if you might want to test by yourself.
Disclaimer: I know that this version is totally confusing and hardly to maintain, but I want to understand, what I am doing wrong here.
thanks for any hints.
Enno
‎2023 Mar 29 1:39 PM
Concerning your main question, why "The origin "fields equal" is always used", the confusion is due to the legibility of your code.
Your code:
field = VALUE #( bapi = VALUE #( components_bapi[ fieldname = component_int-fieldname ]-fieldname
DEFAULT VALUE ts_field( bapi = VALUE #( components_bapi[ fieldname = component_int-deffdname ]-fieldname
DEFAULT VALUE ts_field( bapi = VALUE #( components_bapi[ rollname = component_int-rollname ]-fieldname
DEFAULT VALUE ts_field( bapi = space origin = c_origin_no_match )
) origin = c_origin_rollname_equal )
) origin = c_origin_default_component )
) origin = c_origin_fields_equal ) .is exactly the same as below after switching the 2 components ORIGIN and BAPI:
field = VALUE #( origin = c_origin_fields_equal
bapi = VALUE #( components_bapi[ fieldname = component_bapi-fieldname ]-fieldname
DEFAULT VALUE ts_field( origin = c_origin_default_component bapi = VALUE #( components_bapi[ fieldname = component_bapi-deffdname ]-fieldname
DEFAULT VALUE ts_field( origin = c_origin_rollname_equal bapi = VALUE #( components_bapi[ rollname = component_bapi-rollname ]-fieldname
DEFAULT VALUE ts_field( origin = c_origin_no_match bapi = space )
) ) ) ) ) ).
So you can see more easily that DEFAULT is part of VALUE #( ... ) that you assign to the BAPI component, so you should assign a default value of type FIELDNAME instead of TS_FIELD, and all other ORIGIN initializations are useless/ignored.
‎2023 Mar 28 10:55 AM
I am now clear, why this construction is not working:
The field assignment BAPI = ... can only have the field value, but I am trying to assign a structure (BAPI + ORIGIN).
So I don't think that it is possible to achieve what I want using this VALUE-construct.
If you have any ideas how to retrieve the field AND the origin of the READ in one epxression, feel free to respond.
‎2023 Mar 28 11:20 AM
A one-line solution could be:
field = COND #(
WHEN line_exists( components_bapi[ fieldname = component_int-fieldname ] )
THEN VALUE #( bapi = components_bapi[ fieldname = component_int-fieldname ]-fieldname
origin = c_origin_fields_equal
int = component_int-fieldname )
WHEN line_exists( components_bapi[ fieldname = component_int-deffdname ] )
THEN VALUE #( bapi = components_bapi[ fieldname = component_int-deffdname ]-fieldname
origin = c_origin_default_component
int = component_int-fieldname )
WHEN line_exists( components_bapi[ rollname = component_int-rollname ] )
THEN VALUE #( bapi = components_bapi[ rollname = component_int-rollname ]-fieldname
origin = c_origin_rollname_equal
int = component_int-fieldname )
ELSE VALUE #( bapi = space
origin = c_origin_no_match
int = component_int-fieldname )
).
But it's only a one-line solution of a solution I already tried. I wanted to try to get the work done by the DEFAULT option... 😞
‎2023 Mar 28 4:06 PM
With this last technique, I think you are reading the same line of the table components_bapi 2 times :
- one time with LINE_EXISTS and one time in the THEN VALUE branch
‎2023 Mar 28 9:54 PM
Hi Enno,
I like clear, visible, maintainable codes, and that when in debug there is no doubt about what is happening, so I would never put so many possibilities in one line. That said, anyway, I understood that you know this and were only caught out of curiosity, which also happened to me, and here is what I understood from the case:
I checked documentation and I guess is not possible in one line process the default for the value together with some adjacent settings.
https://help.sap.com/doc/abapdocu_750_index_htm/7.50/en-US/abentable_exp_default_abexa.htm
Check example 1 the lookup is for the structure and default is also structure
DATA(result1) = VALUE #( itab[ id = 1 ] DEFAULT def ).
on example 2 the lookup is to receive a value and default is also a value
DATA(result2) = VALUE #( itab[ id = 1 ]-value DEFAULT def-value ).
So I'm guessing that to achieve use o DEFAULT in one line, you should prepare the table with all variations.
components_bapi2 = VALUE #( ( int = 'NAME1' bapi = 'NAME1' origin = 'E' ) ( int = 'NAME2' bapi = 'NAME2' origin = 'E' ) ( int = 'NAME3' bapi = 'NAME3' origin = 'E' ) ( int = 'NAME4' bapi = 'NAME4' origin = 'E' )
( int = 'NAME3' bapi = 'NAME_TXT' origin = 'D' ) ( int = 'NAME4' bapi = 'NAME4' origin = 'D' )
( int = 'NAME1' bapi = 'CHAR30' origin = 'R' ) ( int = 'NAME2' bapi = 'AD_NAME2' origin = 'R' ) ( int = 'NAME3' bapi = 'AD_NAME' origin = 'R' ) ( int = 'NAME4' bapi = 'AD_NAME_CHK' origin = 'R' ) ).
And find catch the direct line. In this case the default value will lead you to the only option.
field = VALUE #( components_bapi2[ bapi = component_int-fieldname origin = 'E' ]
DEFAULT VALUE #( components_bapi2[ bapi = component_int-deffdname origin = 'D' ]
DEFAULT VALUE #( components_bapi2[ bapi = component_int-rollname origin = 'R' ]
DEFAULT VALUE ( int = component-int-fieldname bapi = '' origin = '-' ) ) ) ).
Despite this explains, for your sample this doesn't seems to be possible prepare a internal table to work properly.Regards, Fernando Da Rós‎2023 Mar 29 9:28 AM
chaouki.akir That's right: the READ will be performed 2 times. But what are the alternatives?
‎2023 Mar 29 9:30 AM
I don't answer your question but the code would be more legible with IF instead of TRY:
DATA(field) = REF ts_field( components_bapi[ fieldname = component_int-fieldname ] OPTIONAL ).
IF field IS BOUND.
field-bapi = field->fieldname.
field-origin = c_origin_fields_equal.
ELSE.
" ETC.
ENDIF.
‎2023 Mar 29 9:39 AM
Thanks for your suggestions 548706 !
If I need to prepare the table first then I do not have any benefit with a one-line-statement afterwards.
In Germany we would call this "von hinten durch die Brust ins Auge". It literally means "from behind through the chest right into the eye" and means that you are doing something complicated although you achieve the correct result. 🙂
In that case I'd rather use a nested read.
I was just curios if I could get rid of the nested structure somehow.
A different solution using OPTIONAL is this one:
field-bapi = VALUE #( components_bapi[ fieldname = component_int-fieldname ]-fieldname OPTIONAL ).
field-origin = c_origin_fields_equal.
IF field-bapi IS INITIAL.
field-bapi = VALUE #( components_bapi[ fieldname = component_int-deffdname ]-fieldname OPTIONAL ).
field-origin = c_origin_default_component.
IF field-bapi IS INITIAL.
field-bapi = VALUE #( components_bapi[ rollname = component_int-rollname ]-fieldname OPTIONAL ).
field-origin = c_origin_rollname_equal.
IF field-bapi IS INITIAL.
field-origin = c_origin_no_match.
ENDIF.
ENDIF.
ENDIF.
APPEND field TO fields.
‎2023 Mar 29 10:32 AM
sandra.rossi here are all variations that I tried in order check readability and performance
‎2023 Mar 29 1:39 PM
Concerning your main question, why "The origin "fields equal" is always used", the confusion is due to the legibility of your code.
Your code:
field = VALUE #( bapi = VALUE #( components_bapi[ fieldname = component_int-fieldname ]-fieldname
DEFAULT VALUE ts_field( bapi = VALUE #( components_bapi[ fieldname = component_int-deffdname ]-fieldname
DEFAULT VALUE ts_field( bapi = VALUE #( components_bapi[ rollname = component_int-rollname ]-fieldname
DEFAULT VALUE ts_field( bapi = space origin = c_origin_no_match )
) origin = c_origin_rollname_equal )
) origin = c_origin_default_component )
) origin = c_origin_fields_equal ) .is exactly the same as below after switching the 2 components ORIGIN and BAPI:
field = VALUE #( origin = c_origin_fields_equal
bapi = VALUE #( components_bapi[ fieldname = component_bapi-fieldname ]-fieldname
DEFAULT VALUE ts_field( origin = c_origin_default_component bapi = VALUE #( components_bapi[ fieldname = component_bapi-deffdname ]-fieldname
DEFAULT VALUE ts_field( origin = c_origin_rollname_equal bapi = VALUE #( components_bapi[ rollname = component_bapi-rollname ]-fieldname
DEFAULT VALUE ts_field( origin = c_origin_no_match bapi = space )
) ) ) ) ) ).
So you can see more easily that DEFAULT is part of VALUE #( ... ) that you assign to the BAPI component, so you should assign a default value of type FIELDNAME instead of TS_FIELD, and all other ORIGIN initializations are useless/ignored.
‎2023 Mar 29 2:17 PM
enno.wulff I just see (late) that you have answered yourself via a comment, you should post it as an answer.
‎2023 Mar 29 1:40 PM
enno.wulff Thanks. As I have shown earlier, I like using REF and IS BOUND, and my snippet does nothing more than what is needed, nothing to guess (provided that people are familiar with REF), e.g. no 2 access like line_exists + Table Expression, no "field-origin = ..." done multiple times and last one is the one which counts, etc.