Skip to Content
Technical Articles
Author's profile photo Mykola Tokariev

Dynamic OData entities declaration

 

In this article I will show an approach to declare OData entities dynamically.

Why?

In case we should change an business logic types and don’t want to change the OData service.

How?

Declare OData entities dynamically.

Contra?

It is more difficult to find the error if something wrong with OData service.

Pro?

It is fast.

In standard case before we start to use OData service we should declare entity types. Basically this is a mapping between business logic types and entity that will be shown for the outside world. In case business logic was changed we should also change the mapping.

Its takes a lot of time especially at the start, where any entities where declared yet. You can see a mapping example below:

METHOD define_dga_in.
    TRY.
        DATA(entity_type) = model->create_entity_type( iv_entity_type_name = zif_business_logic_types=>entity_in
                                                       iv_def_entity_set   = abap_false ).

        properties = VALUE #( ( key = abap_true   property = zif_business_logic_types=>prop_plant          abap = zif_business_logic_types=>field_plant )
                              ( key = abap_false  property = zif_business_logic_types=>prop_tu_number      abap = zif_business_logic_types=>field_tu_number )
                              ( key = abap_true   property = zif_business_logic_types=>prop_matnr          abap = zif_business_logic_types=>field_matnr )
                              ( key = abap_false  property = zif_business_logic_types=>prop_batch_nr       abap = zif_business_logic_types=>field_batch_nr )
                              ( key = abap_false  property = zif_business_logic_types=>prop_bbdate         abap = zif_business_logic_types=>field_bbdate )
                              ( key = abap_false  property = zif_business_logic_types=>prop_brutto         abap = zif_business_logic_types=>field_brutto )
                              ( key = abap_false  property = zif_business_logic_types=>prop_netto          abap = zif_business_logic_types=>field_netto )
                              ( key = abap_false  property = zif_business_logic_types=>prop_tagew          abap = zif_business_logic_types=>field_tagew  )
                              ( key = abap_false  property = zif_business_logic_types=>prop_gewei          abap = zif_business_logic_types=>field_gewei )
                              ( key = abap_false  property = zif_business_logic_types=>prop_menge          abap = zif_business_logic_types=>field_menge )
                              ( key = abap_false  property = zif_business_logic_types=>prop_meins          abap = zif_business_logic_types=>field_meins )
                              ( key = abap_false  property = zif_business_logic_types=>prop_dmeng          abap = zif_business_logic_types=>field_dmeng )
                              ( key = abap_false  property = zif_business_logic_types=>prop_dmein          abap = zif_business_logic_types=>field_dmein )
                              ( key = abap_false  property = zif_business_logic_types=>prop_aufnr          abap = zif_business_logic_types=>field_aufnr )
                              ( key = abap_false  property = zif_business_logic_types=>prop_qplos          abap = zif_business_logic_types=>field_qplos )
                              ( key = abap_false  property = zif_business_logic_types=>prop_lgort          abap = zif_business_logic_types=>field_lgort  )
                              ( key = abap_false  property = zif_business_logic_types=>prop_text           abap = zif_business_logic_types=>field_text )
                              ( key = abap_false  property = zif_business_logic_types=>prop_mess           abap = zif_business_logic_types=>field_mess )
                              ( key = abap_false  property = zif_business_logic_types=>prop_extnr          abap = zif_business_logic_types=>field_extnr ) ).

        create_properties( entity_type ).

        entity_type->bind_structure( iv_structure_name = 'zif_business_logic_types=>in' ).

        entity_type->get_property( zif_business_logic_types=>prop_bbdate )->set_nullable( abap_true ).
        entity_type->get_property( zif_business_logic_types=>prop_bbdate )->set_type_edm_string( ).

        entity_type->get_property( zif_business_logic_types=>prop_gewei )->disable_conversion( ).
        entity_type->get_property( zif_business_logic_types=>prop_meins )->disable_conversion( ).
        entity_type->get_property( zif_business_logic_types=>prop_dmein )->disable_conversion( ).


        DATA(entity_set) = entity_type->create_entity_set( zif_business_logic_types=>entityset_dga_in ).
        entity_set->set_addressable( abap_true ).
        entity_set->set_pageable( abap_true ).
        entity_set->set_filter_required( abap_false ).
      CATCH /iwbep/cx_mgw_med_exception INTO DATA(mgw_error).
        RAISE EXCEPTION mgw_error.
      CATCH /usi/cx_odata.
    ENDTRY.
  ENDMETHOD.

The same result we can achieve with dynamic declaration of entity.

METHOD define_optional_material.
    DATA: data TYPE zif_business_logic_types=>optional_material.

    TRY.
        DATA(entity_type) = model->create_entity_type( iv_entity_type_name = zif_business_logic_types=>entity_optional_material    iv_def_entity_set = abap_false ).

        structure ?= cl_abap_typedescr=>describe_by_data( data ).
        components = structure->components.

        LOOP AT components INTO DATA(comp).
          DATA(pop_entry) = _create_pop_entry( comp ).

          CASE pop_entry-abap.
            WHEN 'EBORT'. pop_entry-key      = abap_true.
          ENDCASE.

          APPEND  pop_entry TO properties.
        ENDLOOP.

        create_properties( entity_type ).

        entity_type->bind_structure( iv_structure_name = CONV #( structure->absolute_name ) ).

        DATA(entity_set) = entity_type->create_entity_set( zif_business_logic_types=>entityset_optional_material ).
        entity_set->set_filter_required( abap_false ).
      CATCH /iwbep/cx_mgw_med_exception INTO DATA(mgw_error).
        RAISE EXCEPTION mgw_error.
      CATCH /usi/cx_odata.
    ENDTRY.

    CLEAR properties.
  ENDMETHOD.

The method _create_prop_entry( comp ) get a component of the structure, that we use in business logic and create properties for the entity. The definition looks like this:

  METHOD _create_pop_entry.
    DATA prop_name TYPE char40.

    prop_name = `prop_`  && i_comp-name.

    ASSIGN zif_business_logic_types=>(prop_name) TO FIELD-SYMBOL(<prop_value>).
    IF <prop_value> IS ASSIGNED.
      r_result-key      = abap_false.
      r_result-property = <prop_value>.
      r_result-abap     = i_comp-name.
    ENDIF.

  ENDMETHOD.

In this case all what we need it is a global declaration of property names. In this case I use an interface for types declaration.

CONSTANTS:
    prop_ebort              TYPE char40 VALUE 'InstallationPointForSubitem',
    prop_upmng              TYPE char40 VALUE 'SubitemQuantity',
    prop_uptxt              TYPE char40 VALUE 'BOMSubitemText'.

That’s all. I hope you got the point.

Summary:

The biggest advantage of this approach you can see if you need to change something in your types. All what you need it is add some new types to you structure and description like as shown above. Your OData service will adapt automatically. Don’t forget to inform your UI colleges about the changes 🙂

Assigned Tags

      Be the first to leave a comment
      You must be Logged on to comment or reply to a post.