Application Development Discussions
Join the discussions or start your own on all things application development, including tools and APIs, programming models, and keeping your skills sharp.
cancel
Showing results forΒ 
Search instead forΒ 
Did you mean:Β 

Nested reads

ennowulff
Active Contributor

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:

  1. Check if fields are equal
  2. Check if default component name of rollname matches the BAPI fieldname
  3. Check if rollnames are equal

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

1 ACCEPTED SOLUTION

Sandra_Rossi
Active Contributor
0 Kudos

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.
11 REPLIES 11

ennowulff
Active Contributor
0 Kudos

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.

ennowulff
Active Contributor

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... 😞

chaouki_akir
Contributor
0 Kudos

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

fedaros
Contributor
0 Kudos

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

ennowulff
Active Contributor
0 Kudos

chaouki.akir That's right: the READ will be performed 2 times. But what are the alternatives?

Sandra_Rossi
Active Contributor
0 Kudos

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.

ennowulff
Active Contributor
0 Kudos

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.

ennowulff
Active Contributor

sandra.rossi here are all variations that I tried in order check readability and performance

Sandra_Rossi
Active Contributor
0 Kudos

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.

enno.wulff I just see (late) that you have answered yourself via a comment, you should post it as an answer.

Sandra_Rossi
Active Contributor
0 Kudos

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.