cancel
Showing results for 
Search instead for 
Did you mean: 

ABAP Rest Full Custom entities association is not working for navigating to detail page

DucourtyEtan
Discoverer
0 Kudos
300

Hey everyone,

 
I have followed this blog :
SAP ABAP RAP : Custom Entities with compositions relationship in a Fiori Elements App 

And now I have a problem

 

In our system (S4 2022, 757 Basis), we have tried to reproduce this development.

We have two custom entities:

- One ZC_OMNIBUS_TILE

 

@EndUserText.label: 'Data def tile omnibus'
@ObjectModel.query.implementedBy: 'ABAP:ZCL_OMNIBUS_TILE'

@UI.headerInfo: {
    typeName: 'Omnibus',
    typeNamePlural: 'Omnibus',
    title: {
    type: #STANDARD,
    value: 'matnr'
    },
    description: {
    type: #STANDARD,
    value: 'msgtxt'
    }
  }

define root custom entity ZC_OMNIBUS_TILE
{


      @ui.facet             : [{
                   id       :  'General',
                   purpose  :  #STANDARD,
                   parentId : '',
                   position : 10,
                   isPartOfPreview: true,
                   label    :  'General',
                   type     :  #COLLECTION,
                   targetQualifier: 'General'
                   },
                    {
                   id       : 'BasicInfo',
                   purpose  : #STANDARD,
                   parentId : 'General',
                   position : 10,
                   isPartOfPreview: true,
                   label    : 'Basic Info',
                   type     :  #FIELDGROUP_REFERENCE,
                   targetQualifier: 'QFBasicInfo'
                   },
                   {
                   id       : 'ProductInfo',
                   purpose  : #QUICK_VIEW,
                   parentId : 'General',
                   position : 20,
                   isPartOfPreview: true,
                   label    : 'Product Info',
                   type     :  #FIELDGROUP_REFERENCE,
                   targetQualifier: 'QFProductInfo'
                   },
                   {
                   id         : 'Items',
                   purpose    : #STANDARD,
                   position   : 30,
                   label      : 'Items',
                   type       :  #LINEITEM_REFERENCE,
                   targetElement: '_OmnibusHeaderHisto'
                  
                   }]

      @ui.lineItem        : [{ position: 10 }]
      @ui .identification : [{position: 10}]
      @ui.fieldGroup      : [ { type: #STANDARD,  position: 10 ,  qualifier: 'QFBasicInfo'  } ]
  key row_id              : lineid;

      @ui.lineItem        : [{ position: 20 }]
      @ui.selectionField  : [{position: 20}]
      @ui.identification  : [{position: 20}]
      @ui.fieldGroup      : [ { type: #STANDARD,  position: 20 ,  qualifier: 'QFProductInfo'  } ]
  key matnr               : matnr;

      @ui.lineItem        : [{ position: 30 }]
      @ui.selectionField  : [{position: 30}]
      @ui.identification  : [{position: 30}]
      @ui.fieldGroup      : [ { type: #STANDARD,  position: 30 ,  qualifier: 'QFProductInfo'  } ]
      werks               : werks_d;

      @ui.selectionField  : [{position: 40}]
      @Consumption.filter.selectionType: #SINGLE
      @ui.fieldGroup      : [ { type: #STANDARD,  position: 40 ,  qualifier: 'QFProductInfo'  } ]
      sales_org           : vkorg;

      @ui.lineItem        : [{ position: 50 }]
      @ui.identification  : [{position: 50}]
      @Semantics.amount.currencyCode: 'currency'
      @ui.fieldGroup      : [ { type: #STANDARD,  position: 50 ,  qualifier: 'QFProductInfo'  } ]
      kbetr_promo         : ze_kbetr_promo;

      @ui.lineItem        : [{ position: 60 }]
      @ui.selectionField  : [{position: 60}]
      @Consumption.filter.selectionType: #SINGLE
      @ui.identification  : [{position: 60}]
      @ui.fieldGroup      : [ { type: #STANDARD,  position: 60 ,  qualifier: 'QFProductInfo'  } ]
      datab_promo         : /sapapo/pm_startdate;

      @ui.lineItem        : [{ position: 70 }]
      @ui.identification  : [{position: 70}]
      @ui.fieldGroup      : [ { type: #STANDARD,  position: 70 ,  qualifier: 'QFProductInfo'  } ]
      datbi_promo         : /sapapo/pm_lastdate;

      @ui.lineItem        : [{ position: 80}]
      @ui.identification  : [{position: 80}]
      @ui.fieldGroup      : [ { type: #STANDARD,  position: 80 ,  qualifier: 'QFProductInfo'  } ]
      @Semantics.amount.currencyCode: 'currency'
      kbetr_omnibus       : ze_kbetr_omnibus;

      @ui.lineItem        : [{ position: 90}]
      @ui.identification  : [{position: 90}]
      @ui.fieldGroup      : [ { type: #STANDARD,  position: 90 ,  qualifier: 'QFProductInfo'  } ]
      msgtxt              : msgtxt;

      @Semantics.currencyCode
      currency            : waers;


      _OmnibusHeaderHisto : composition [0..*] of ZC_OMNIBUS_TILE_HISTO;
}

 

- and the other for Object navigation which will have the details (several lines for this "header")

 

@EndUserText.label: 'Data def tile omnibus for histo part'
@ObjectModel.query.implementedBy: 'ABAP:ZCL_OMNIBUS_TILE'

@UI.headerInfo: {
    typeName: 'OmnibusHisto',
    typeNamePlural: 'OmnibusHisto',
    title: {
    type: #STANDARD,
    value: 'matnr'
    },
    description: {
    type: #STANDARD,
    value: 'tabname'
    }
  }

define custom entity ZC_OMNIBUS_TILE_HISTO
{

      @ui.facet       : [{
                         id      :  'General',
                         purpose :  #STANDARD,
                         position: 10,
                         label   :  'Omnibus',
                         type    :  #IDENTIFICATION_REFERENCE
                         }]

      @ui.hidden      : true
  key row_id          : lineid;

      @ui.lineItem    : [{ position: 10 }]
      @ui.identification      : [{ position: 5 }]
  key matnr           : matnr;

      @ui.lineItem    : [{ position: 20 }]
      @ui.identification      : [{ position: 10 }]
      num_ett         : char4;

      @ui.lineItem    : [{ position: 30 }]
      @ui.identification      : [{ position: 20 }]
      num_cond        : char20;

      @ui.lineItem    : [{ position: 40 }]
      @ui.identification      : [{ position: 30 }]
      val_prx         : char15;

      @ui.lineItem    : [{ position: 50 }]
      @ui.identification      : [{ position: 40 }]
      val_cond        : char15;

      @ui.lineItem    : [{ position: 60 }]
      @ui.identification      : [{ position: 50 }]
      cod_dev         : char3;

      @ui.lineItem    : [{ position: 70 }]
      @ui.identification      : [{ position: 60 }]
      mains           : meins;

      @ui.lineItem    : [{ position: 80 }]
      @ui.identification      : [{ position: 70 }]
      dat_debvalidmag : dats;

      @ui.lineItem    : [{ position: 90 }]
      @ui.identification      : [{ position: 80 }]
      dat_finvalidmag : dats;

      @ui.lineItem    : [{ position: 100 }]
      @ui.identification      : [{ position: 90 }]
      code_eca_pric   : zecode_ecart;

      @ui.lineItem    : [{ position: 110 }]
      @ui.identification      : [{ position: 100 }]
      tabname         : tabname;


      _OmnibusHeader  : association to parent ZC_OMNIBUS_TILE on  $projection.row_id = _OmnibusHeader.row_id
                                                              and $projection.matnr  = _OmnibusHeader.matnr;

}

 

 

We have set on service definition 

 

@EndUserText.label: 'Service definition for omnibus tile'
define service ZSD_OMNIBUS_TILE {
  expose ZC_OMNIBUS_TILE as OmnibusHeader;
  expose ZC_OMNIBUS_TILE_HISTO as OmnibusHeaderHisto;
}

 

and only one service binding in OData V4 - UI and no behavior definition

The first page display correctly the information but when we want to nagivate to the object page, in the custom entity class we do not retrieve the entity ZC_OMNIBUS_TILE_HISTO. The front end generate only 2 batch request for ZC_OMNIBUS_TILE.

 

    CASE io_request->get_entity_id( ).

      WHEN 'ZC_OMNIBUS_TILE'.
"do selection

      WHEN 'ZC_OMNIBUS_TILE_HISTO'.
"do the history selection

    ENDCASE.

 

We do not understand what is wrong ?

Hoping someone can help me

Thanks you in advance for your reply

View Entire Topic
MaryiaHlushko
Product and Topic Expert
Product and Topic Expert

Hi @DucourtyEtan ,

It seems to me that you can have some issue with filtering or paging.

I will share with you a simplified example of two custom entities with a parent-child relationship. There you also find the example of code that handles filtering, paging, and sorting functionality for custom entities.

ZMHL_C_CUSTOM_HEADER - parent custom entity.

@ObjectModel.query.implementedBy: 'ABAP:ZMHL_CL_CUSTOM_ENTITY'
@EndUserText.label: 'Header'
@UI: {
  headerInfo: {
    typeName: 'Header',
    typeNamePlural: 'Headers',
    title: { type: #STANDARD, label: 'Header', value: 'HeaderID' }
  }}
define root custom entity ZMHL_C_Custom_Header
{
      @UI.facet   : [
                       {
                          id    :   'Header',
                          purpose:  #STANDARD,
                          type  :   #IDENTIFICATION_REFERENCE,
                          label :   'Header',
                          position: 10
                       },
                       {
                            id  : 'Item',
                            purpose   : #STANDARD,
                            type: #LINEITEM_REFERENCE,
                            label     : 'Items',
                            position  : 20,
                            targetElement: '_Item'
                       } ]
                       
      @UI.lineItem          : [ { position: 10 } ]
      @UI.identification    : [ { position: 10 } ]
      @EndUserText.label    : 'Header ID'
  key HeaderID    : abap.numc( 3 );
  
      @UI.lineItem          : [ { position: 20 } ]
      @UI.identification    : [ { position: 20 } ]
      @EndUserText.label    : 'Description'
      Description : abap.char(40);

      _Item       : composition [1..*] of ZMHL_C_Custom_Item;
}

ZMHL_C_CUSTOM_ITEM - child custom entity.

@ObjectModel.query.implementedBy: 'ABAP:ZMHL_CL_CUSTOM_ENTITY'
@EndUserText.label: 'Item'
@UI: {
  headerInfo: {
    typeName: 'Item',
    typeNamePlural: 'Items',
    title: { type: #STANDARD, label: 'Item', value: 'Item' }
  }}
define custom entity ZMHL_C_Custom_Item
{
      @UI.facet   : [ { id    :   'Item',
                        purpose:  #STANDARD,
                        type  :   #IDENTIFICATION_REFERENCE,
                        label :   'Item',
                        position: 10 } ]
      @UI.hidden  : true
  key HeaderID    : abap.numc( 3 );
  
      @UI.lineItem: [ { position: 10 } ]
      @UI.identification    : [ { position: 10 } ]
      @EndUserText.label    : 'Item'
  key Item        : abap.numc( 2 );
  
      @UI.lineItem: [ { position: 20 } ]
      @UI.identification    : [ { position: 20 } ]
      @EndUserText.label    : 'Description'
      Description : abap.char( 40 );

      _Header     : association to parent ZMHL_C_Custom_Header on _Header.HeaderID = $projection.HeaderID;
}

ZMHL_CL_CUSTOM_ENTITY - class with implementation for both custom entities Header and Item. Filtering and sorting functionality is implemented using the ability of SELECT statements with dynamic WHERE and ORDER BY clauses. Paging functionality is implemented by UP TO n ROWS and OFFSET clauses of SELECT statement.

CLASS zmhl_cl_custom_entity DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.
    INTERFACES: if_rap_query_provider.
  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.



CLASS zmhl_cl_custom_entity IMPLEMENTATION.
  METHOD if_rap_query_provider~select.
    DATA: lt_header   TYPE STANDARD TABLE OF zmhl_c_custom_header,
          lt_item     TYPE STANDARD TABLE OF zmhl_c_custom_item,
          lv_order_by TYPE string.

    lt_header = VALUE #( ( headerid = '001' description = 'Header 1' )
                         ( headerid = '002' description = 'Header 2' )
                         ( headerid = '003' description = 'Header 3' ) ).
    lt_item = VALUE #( 
                 ( headerid = '001' item = '01' description = 'Item 1.1' )
                 ( headerid = '001' item = '02' description = 'Item 1.2' )
                 ( headerid = '001' item = '03' description = 'Item 1.3' )
                 ( headerid = '002' item = '01' description = 'Item 2.1' )
                 ( headerid = '002' item = '02' description = 'Item 2.2' )
                 ( headerid = '003' item = '01' description = 'Item 3.1' ) ).
    "Get Filters
    DATA(lv_filter) =  io_request->get_filter( )->get_as_sql_string( ).

    "Get paging properties
    DATA(lv_offset) = io_request->get_paging( )->get_offset( ).
    "Get positive page size, to avoid -1
    DATA(lv_page_size) = abs( io_request->get_paging( )->get_page_size( ) ).

    "Get sorting
    DATA(lt_sort_elements) = io_request->get_sort_elements( ).
    LOOP AT lt_sort_elements ASSIGNING FIELD-SYMBOL(<fs_sort_element>).
      lv_order_by = |{ lv_order_by }{ COND #( 
                 WHEN <fs_sort_element>-descending = abap_false
                 THEN |, { <fs_sort_element>-element_name }|
                 ELSE |, { <fs_sort_element>-element_name } DESCENDING| ) }|.
    ENDLOOP.
    SHIFT lv_order_by BY 2 PLACES LEFT.

    CASE io_request->get_entity_id( ).

      WHEN 'ZMHL_C_CUSTOM_HEADER'.
        "Apply filter, get table with all results
        SELECT * FROM @lt_header AS header
        WHERE (lv_filter)
        INTO TABLE @DATA(lt_header_result).

        "Apply paging and sorting, get requested part of results
        IF lv_order_by IS INITIAL.
          lv_order_by = |HEADERID|.
        ENDIF.
        SELECT * FROM @lt_header_result AS header
          ORDER BY (lv_order_by)
          INTO TABLE @DATA(lt_requested_header)
          UP TO @lv_page_size ROWS OFFSET @lv_offset.

        "set total count of results
        IF io_request->is_total_numb_of_rec_requested(  ).
          io_response->set_total_number_of_records( lines( lt_header_result ) ).
        ENDIF.
        "set data
        io_response->set_data( lt_requested_header ).

      WHEN 'ZMHL_C_CUSTOM_ITEM'.

        "Apply filter, get table with all results
        SELECT * FROM @lt_item AS item
          WHERE (lv_filter)
          INTO TABLE @DATA(lt_item_result).

        "Apply paging and sorting, get requested part of results
        IF lv_order_by IS INITIAL.
          lv_order_by = |ITEM|.
        ENDIF.
        SELECT * FROM @lt_item_result AS item
         ORDER BY (lv_order_by)
         INTO TABLE @DATA(lt_requested_item)
         UP TO @lv_page_size ROWS OFFSET @lv_offset.

        "set total count of results
        IF io_request->is_total_numb_of_rec_requested(  ).
          io_response->set_total_number_of_records( lines( lt_item_result ) ).
        ENDIF.
        "set data
        io_response->set_data( lt_requested_item ).

    ENDCASE.

  ENDMETHOD.

ENDCLASS.

 

Service binding in OData V4. Service definition: 

@EndUserText.label: 'Custom Entity Service Definition'
define service ZMHL_Custom_Entity {
  expose ZMHL_C_Custom_Header;
  expose ZMHL_C_Custom_Item;
}

Application demo:

Custom Entity with composition.gif

I hope it will help you to solve the issue.

Best Regards,

Maryia

DucourtyEtan
Discoverer
0 Kudos

Hi @MaryiaHlushko

Thank you very much for your answer that unblocked me.