Application Development Blog Posts
Learn and share on deeper, cross technology development topics such as integration and connectivity, automation, cloud extensibility, developing at scale, and security.
cancel
Showing results for 
Search instead for 
Did you mean: 
lukcad
Explorer

Overview

-- Goal:

Using SAP instance with SAP NW 7.40 or higher without RAP and without BOPF be able to create OData service upon business data model with these specific requirements:

- inserting of main business record support deep inserting (we save main record of main entity and all enclosed records in child entity)

- all CRUD methods of modification records for entities should be supported .

- code after regenerating OData service after adding of new changes is under control of developer via implemented overridden methods.

-- Considered model:

lukcad_0-1714379019619.png

-- Main steps of implementation:

Using Eclipse + ADT you will go through this main steps and with all necessary code:

1-- Prepare data model with data

2-- Create project for OData service

3-- Add data model and generate service

4-- Register service and do initial test

5-- Implementation of `deep insert` MODEL via override

6-- Implementation of entity modification methods

7-- Implementation of OData CRUD methods using override

8-- Testing CRUD methods by SAP Gateway Client

9-- Verification of achieved code

-- As result of you will have:

-- Transportable package ZMLODATA which includes:

-- Data model with samples of data

-- OData service ZML_TRAVELLING_ODT

-- Classes where _EXT implementation decupled from regenerating process of OData service

Package ZMLODATA will contain these files:

lukcad_1-1714379019620.png

Service Project `ZML_TRAVELLING_ODT` will be like this one:

lukcad_2-1714379019622.png

Process of implementation

1-- Prepare data model with data

1--1-- create package ZMLODATA

1--2-- create data elements in package

 

ZMLNAME

lukcad_3-1714379019623.png

 

 

ZMLDATEFROM

lukcad_4-1714379019623.png

 

 

ZMLDATETO

lukcad_5-1714379019624.png

 

 

1--3-- create table ZML_TRAVEL

Using package ZMLODATA you create database table in Eclipse ADT by opening `New ABAP Repository Object` for `Database Table`  and using this code definition:

 

@EndUserText.label : 'ZML_TRAVEL'
@AbapCatalog.enhancementCategory : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #ALLOWED
define table zml_travel {
  key client    : abap.clnt not null;
  key travel_id : sysuuid_x16 not null;
  name          : zmlname;

}

1--4-- create table ZML_BOOKING

You add new Database Table `ZML_BOOKING` by this code into package ZMLODATA:

@EndUserText.label : 'ZML_BOOKING'
@AbapCatalog.enhancementCategory : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #ALLOWED
define table zml_booking {
  key client     : abap.clnt not null;
  @AbapCatalog.foreignKey.screenCheck : false
  key travel_id  : sysuuid_x16 not null
    with foreign key [0..*,1] zml_travel
      where travel_id = zml_booking.travel_id;
  key booking_id : sysuuid_x16 not null;
  hotel          : zmlname;
  dayfrom        : zmldatefrom;
  dayto          : zmldateto;

}

1--5-- Create Class `zml_gen_data_travels`

In package ZMLODATA you add new ABAP class `zml_gen_data_travels` by this code: 

CLASS zml_gen_data_travels DEFINITION
  PUBLIC
  FINAL
  CREATE PUBLIC .

  PUBLIC SECTION.

    INTERFACES if_oo_adt_classrun .
  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.



CLASS zml_gen_data_travels IMPLEMENTATION.
  METHOD if_oo_adt_classrun~main.

    DATA it_travel TYPE TABLE OF zml_travel.
    DATA it_booking TYPE TABLE OF zml_booking.

    DATA lv_long_time_stamp TYPE timestampl.
    GET TIME STAMP FIELD lv_long_time_stamp.
    DATA: l_uuid_x16 TYPE sysuuid_x16.
    DATA: system_uuid TYPE REF TO if_system_uuid.
    DATA: oref        TYPE REF TO cx_uuid_error.
    system_uuid = cl_uuid_factory=>create_system_uuid( ).

    TRY.

        it_travel =  VALUE #(
          ( client = sy-mandt travel_id = system_uuid->create_uuid_x16( ) name = 'Travel Minsk - Dubai' )
          ( client = sy-mandt travel_id = system_uuid->create_uuid_x16( ) name = 'Travel Minsk - Moscow' )
          ( client = sy-mandt travel_id = system_uuid->create_uuid_x16( ) name = 'Travel Minsk - Warsaw' )
          ( client = sy-mandt travel_id = system_uuid->create_uuid_x16( ) name = 'Travel Minsk - Dushanbe' )
          ( client = sy-mandt travel_id = system_uuid->create_uuid_x16( ) name = 'Travel Minsk - Batumi' )

        ).

        it_booking = VALUE #(
            ( client = sy-mandt booking_id = system_uuid->create_uuid_x16( ) travel_id = it_travel[ name = 'Travel Minsk - Dubai' ]-travel_id dayfrom = '20240101'  dayto = '20240104' hotel = 'Amirates Dubai' )
            ( client = sy-mandt booking_id = system_uuid->create_uuid_x16( ) travel_id = it_travel[ name = 'Travel Minsk - Moscow' ]-travel_id dayfrom = '20240105'  dayto = '20240107' hotel = 'Marriot' )
            ( client = sy-mandt booking_id = system_uuid->create_uuid_x16( ) travel_id = it_travel[ name = 'Travel Minsk - Warsaw' ]-travel_id dayfrom = '20240108'  dayto = '20240114' hotel = 'Outstanding WSW' )
            ( client = sy-mandt booking_id = system_uuid->create_uuid_x16( ) travel_id = it_travel[ name = 'Travel Minsk - Dushanbe' ]-travel_id dayfrom = '20240115'  dayto = '20240124' hotel = 'Marriot Hayat' )
            ( client = sy-mandt booking_id = system_uuid->create_uuid_x16( ) travel_id = it_travel[ name = 'Travel Minsk - Batumi' ]-travel_id dayfrom = '20240125'  dayto = '20240130' hotel = 'Amber Sea' )
        ).

        out->write( it_travel ).
        out->write( it_booking ).

*       delete existing entries in the database table
        DELETE FROM zml_booking.
        DELETE FROM zml_travel.


*       insert the new table entries
        INSERT zml_travel FROM TABLE @IT_travel.
        INSERT zml_booking FROM TABLE @IT_booking.

        out->write( |Demo data generated for tables...| ).

      CATCH cx_uuid_error.
        "handle exception
    ENDTRY.



  ENDMETHOD.

ENDCLASS.

1--6-- Run this class by pressing F9

You execute previously created class to add initial records into your data model by pressing F9.

5 records with travels and 5 records connected to each travel for bookings will be added after executing.

lukcad_6-1714379019625.png

1--7-- at this moment you should have package with your dictionary and class

lukcad_7-1714379019627.png

1--8-- you open data tables by preview of data  to find that test records exist:

lukcad_8-1714379019628.png

lukcad_9-1714379019629.png

2-- create project for OData service

You press Alt-F8 and enter and run transaction: SEGW

In opened form you press icon of "Create project"

lukcad_10-1714379019629.png

You fill in this information on form of creating project:

Project

ZML_TRAVELLING_ODT

Description

OData for travelling data

Package

ZMLODATA

You get a project `ZML_TRAVELLING_ODT` which has initial skeleton without connectivity to your model at this moment:

lukcad_11-1714379019630.png

3-- Add data model and generate service

Using project `ZML_TRAVELLING_ODT` you do the next steps to import your entitles of model one by one, make necessary association between entities and generate project.

3--1-- Add Entity Type for ZML_TRAVEL table

Change project `ZML_TRAVELLING_ODT` to Edit mode.

Using context menu of Data model node you have to choose: Import -> DDIC Stucture

lukcad_12-1714379019630.png

On first step of import wizard you provide the next information:

Name of type which we want create:

ZML_ITRAVEL

ABAP Structure (existing our table):

ZML_TRAVEL

lukcad_13-1714379019631.png

On second step mark all fields:

lukcad_14-1714379019631.png

On third step point the key of your records as TRAVEL_ID

lukcad_15-1714379019632.png

In imported properties provide correctly operations:

lukcad_16-1714379019632.png

if you open Entity Sets you should be able to find there `ZML_ITRAVELSet`

lukcad_17-1714379019633.png

3--2-- Add Entity Type for ZML_BOOKING table

Again, you using context menu of Data model node choose Import -> DDIC Structure to open Wizard of importing.

On the first step of import wizard you provide:

Name of type which we want create:

ZML_IBOOKING

ABAP Structure (existing our table):

ZML_BOOKING

On second step of wizard you select all fields of entity.

And on the 3d  step of wizard you point key id BOOKING_ID :

lukcad_18-1714379019634.png

3--3-- Add association between ZML_ITRAVEL and ZML_IBOOKING

Using context menu on Association node you choose `Create` to start the wizard of creating association.

lukcad_19-1714379019635.png

You should provide these parameters on Step 1 of association wizard:

Association Name

ZML_TRAVEL_TO_BOOKING

Principal Entity Type Name

ZML_ITRAVEL

Principal Cardinality

1

Principal Navigation Property

TO_BOOKING

Dependent Entity Type Name

ZML_IBOOKING

Dependent Cardinality

0..n

Dependent Navigation Property

 

On Step 2 of wizard association you point principal key TravelId for `Dependent Property`:

lukcad_20-1714379019635.png

On Step 3 of wizard association you press Finish

lukcad_21-1714379019636.png

You can check association in node Associations:

lukcad_22-1714379019636.png

Also, you can check as `Navigation Property` with name `TO_BOOKING` if you expand Entity Types nodes in Data Model of project. The existence of this navigation property after applying association and the name `TO_BOOKING` we will use for `expand` functionality as well as for `deep insert` functionality

lukcad_23-1714379019637.png

3--4-- Generate Runtime Objects of OData service

You press icon `Generate Runtime Objects`

lukcad_24-1714379019638.png

As a result, 4 classes with prefix `ZCL_` will be generated in your package. Currently, all methods to serve ZML_IBTRAVELSET and ZML_IBOOKINGSET entity types will be pre-filled in with pattern of raising exception to generate message that method is not implemented yet.  Later on, you will do implementation of each method in classes with `_EXT` suffix by overriding methods.

lukcad_25-1714379019638.png

4-- Register service and do initial test

You should register service into SAP gateway and verify that service is maintained by initial test. It is better to do now, before you start implementation of methods to let you be ensured that service engin is generated correctly and you were able to maintain it correctly into SAP Gateway.

4--1-- Register service

In project open node `Service maintenance` and choose accessible SAP Gateway and press button `+Register` and then on prefilled form choose package ZMLODATA and save registration.

lukcad_26-1714379019639.png

After registration you will be re-directed to Service Maintenance list ( also you can use transaction to be there in any time: /IWFND/MAINT_SERVICE ) where you can choose your service by technical name 1ZML_TRAVELLING_ODT`.

4--2-- Initial test

Once your service is registered you can test it by `SAP Gateway Client` through opening Maintenance list and then after choosing your service using ICF Nodes panel do pressing on `SAP Gateway Client` or you can directly start testing client form Service Maintenance of chosen gateway by pressing button `SAP Gateway Client` on form of Service registration.

Press `SAP Gateway Client` and and execute proposed URI and check that you have HTTP response with status 200 OK

lukcad_27-1714379019640.png

change URI to ask provide operations with format JSON (just change format=xml to format=json)

/sap/opu/odata/sap/ZML_TRAVELLING_ODT_SRV/?$format=json

and execute to verify that you can get JSON response with status 200 Ok :

lukcad_28-1714379019642.png

So currently OData which you created has information about your entities but if you try to use those entities (datasets) you will have error, because entities are not still connected to your data in databases.

if you will try to run this request:

/sap/opu/odata/sap/ZML_TRAVELLING_ODT_SRV/ZML_ITRAVELSet?$format=json

instead of data in response you will find error 501 and message "Method 'ZML_ITRAVELSET_GET_ENTITYSET' not implemented in data provider class"

lukcad_29-1714379019643.png

In next steps (5,6,7) you will implement all necessary methods.

5-- Implementation of `deep insert` MODEL via override

As developer, you should modify class which is dedicated for extending object model of implementation: `zcl_zml_travelling_odt_mpc_ext` where name of class is proposed during generating service and the name of class for extending model by default is a combination:  `ZCL`_ + <name_of_service> + `_MPC_EXT`

you will add manually the new deep structure there and do override of existing method `define` to be able map structure to certain entity.

This implementation is important to enable using structure for `deep insert` which will be needing to write correctly code for method CREATE of entity ZML_ITRAVELSet,.

5--1-- Add structure for `deep insert`

Open class for extending `zcl_zml_travelling_odt_mpc_ext` which is here:

lukcad_30-1714379019643.png

You should add new type for structure of deep insert which is based on your types of data sets.

Goal to create hierarchy of types:

lukcad_50-1714381260523.png

In public section of extension class zcl_zml_travelling_odt_mpc_ext you should add new structure:

    TYPES: BEGIN OF ty_s_trv_book.
             INCLUDE TYPE zcl_zml_travelling_odt_mpc=>ts_zml_itravel.
    TYPES:
             to_booking TYPE STANDARD TABLE OF zcl_zml_travelling_odt_mpc=>ts_zml_ibooking WITH DEFAULT KEY,
           END OF ty_s_trv_book.

Name of structure for this particular example is `ty_s_trv_book`.

5--2-- Override method `define`

Open in editor class zcl_zml_travelling_odt_mpc_ext and press Ctrl + space and choose Override `define`.

In overridden method is main aim is to map entity type of service to new structure of `deep insert`. Code of overridden method `define`:

  METHOD define.

    DATA lo_entity_type TYPE REF TO /iwbep/if_mgw_odata_entity_typ.

    super->define( ).

    lo_entity_type = model->get_entity_type( iv_entity_name = 'ZML_ITRAVEL' ).
    lo_entity_type->bind_structure( iv_structure_name = 'zcl_zml_travelling_odt_mpc_ext=>ty_s_trv_book' ).

  ENDMETHOD.

 

5--3-- Full code of extension method after preparation of `deep insert`:

CLASS zcl_zml_travelling_odt_mpc_ext DEFINITION
  PUBLIC
  INHERITING FROM zcl_zml_travelling_odt_mpc
  CREATE PUBLIC .

  PUBLIC SECTION.
    TYPES: BEGIN OF ty_s_trv_book.
             INCLUDE TYPE zcl_zml_travelling_odt_mpc=>ts_zml_itravel.
    TYPES:
             to_booking TYPE STANDARD TABLE OF zcl_zml_travelling_odt_mpc=>ts_zml_ibooking WITH DEFAULT KEY,
           END OF ty_s_trv_book.

    METHODS define REDEFINITION.



  PROTECTED SECTION.
  PRIVATE SECTION.
ENDCLASS.



CLASS zcl_zml_travelling_odt_mpc_ext IMPLEMENTATION.

  METHOD define.

    DATA lo_entity_type TYPE REF TO /iwbep/if_mgw_odata_entity_typ.

    super->define( ).

    lo_entity_type = model->get_entity_type( iv_entity_name = 'ZML_ITRAVEL' ).
    lo_entity_type->bind_structure( iv_structure_name = 'zcl_zml_travelling_odt_mpc_ext=>ty_s_trv_book' ).

  ENDMETHOD.

ENDCLASS.

6-- Implementation of entity modification methods

As developer, you should modify class which is dedicated for extending methods to work with data: `zcl_zml_travelling_odt_dpc_ext` where name of class is proposed during generating service and the name of class for extending data methods is combination of by default:  `ZCL`_ + <name_of_service> + `_DPC_EXT`

Before start extending OData CRUD methods, you add 3 custom methods in this particular case:

6--1-- add custom method `zml_create_uuid` for getting UUID:

In protected section of class definition add:

    METHODS zml_create_uuid
      RETURNING VALUE(es_uuid) TYPE sysuuid_x16.

In implementation area of class add:

  METHOD zml_create_uuid.
    DATA lv_long_time_stamp TYPE timestampl.
    GET TIME STAMP FIELD lv_long_time_stamp.
    DATA: l_uuid_x16 TYPE sysuuid_x16.
    DATA: system_uuid TYPE REF TO if_system_uuid.
    DATA: oref        TYPE REF TO cx_uuid_error.
    system_uuid = cl_uuid_factory=>create_system_uuid( ).

    TRY.
        es_uuid = system_uuid->create_uuid_x16( ).
      CATCH cx_uuid_error.
        "handle exception
    ENDTRY.
  ENDMETHOD.

 

6--2-- add custom method `zml_modify_travel` for update or insert ZML_TRAVEL entity:

In protected section of class definition add:

    METHODS zml_modify_travel
      IMPORTING
                !ls_entity       TYPE zcl_zml_travelling_odt_mpc=>ts_zml_itravel
      RETURNING VALUE(es_entity) TYPE zcl_zml_travelling_odt_mpc=>ts_zml_itravel.

 In implementation area of class add:

  METHOD zml_modify_travel.
    DATA:
      it_entity TYPE zcl_zml_travelling_odt_mpc=>ts_zml_itravel.
    MOVE-CORRESPONDING ls_entity TO it_entity.
    IF ( it_entity-client IS INITIAL ).
      it_entity-client = sy-mandt.
    ENDIF.
    TRY.
        it_entity-name = ls_entity-name.
        DATA itb_entity TYPE TABLE OF zml_travel.
        IF ( it_entity-travel_id IS INITIAL ).
          it_entity-travel_id = zml_create_uuid( ).
          itb_entity = VALUE #( ( it_entity )  ).
          INSERT zml_travel FROM TABLE @itb_entity.
        ELSE.
          itb_entity = VALUE #( ( it_entity )  ).
          MODIFY zml_travel FROM TABLE @itb_entity.
        ENDIF.
        es_entity = it_entity.
      CATCH cx_uuid_error.
    ENDTRY.
  ENDMETHOD.

 

6--3-- add custom method `zml_modify_booking` for update or insert ZML_BOOKING entity:

In protected section of class definition add:

    METHODS zml_modify_booking
      IMPORTING
                !ls_entity       TYPE zcl_zml_travelling_odt_mpc=>ts_zml_ibooking
      RETURNING VALUE(es_entity) TYPE zcl_zml_travelling_odt_mpc=>ts_zml_ibooking.

 In implementation area of class add:

  METHOD zml_modify_booking.
    DATA:
    it_entity TYPE zcl_zml_travelling_odt_mpc=>ts_zml_ibooking.
    MOVE-CORRESPONDING ls_entity TO it_entity.
    IF ( ls_entity-client IS INITIAL ).
      it_entity-client = sy-mandt.
    ENDIF.
    IF ( ls_entity-travel_id IS NOT INITIAL ).
      TRY.
          DATA itb_entity TYPE TABLE OF zml_booking.
          IF ( it_entity-booking_id IS INITIAL ).
            it_entity-booking_id = zml_create_uuid( ).
            itb_entity = VALUE #( ( it_entity )  ).
            INSERT zml_booking FROM TABLE @itb_entity.
          ELSE.
            itb_entity = VALUE #( ( it_entity )  ).
            MODIFY zml_booking FROM TABLE @itb_entity.
          ENDIF.
          es_entity = it_entity.
        CATCH cx_uuid_error.
      ENDTRY.
    ENDIF.

  ENDMETHOD.

    

6--4-- add custom method `deep_insert_travel_booking` for insert ZML_TRAVEL and ZML_BOOKING entities:

In protected section of class definition add:

    METHODS deep_insert_travel_booking
      IMPORTING
        !io_data_provider TYPE REF TO /iwbep/if_mgw_entry_provider
      EXPORTING
        !es_s_trv_book    TYPE zcl_zml_travelling_odt_mpc_ext=>ty_s_trv_book
      RAISING
        /iwbep/cx_mgw_busi_exception
        /iwbep/cx_mgw_tech_exception .

  In implementation area of class add:

  METHOD deep_insert_travel_booking.
    DATA: ls_travel_booking_data TYPE zcl_zml_travelling_odt_mpc_ext=>ty_s_trv_book.
    DATA: ls_entity TYPE zcl_zml_travelling_odt_mpc=>ts_zml_itravel.
    DATA: ls_childentity TYPE zcl_zml_travelling_odt_mpc=>ts_zml_ibooking.
    DATA: ar_childentities TYPE STANDARD TABLE OF zcl_zml_travelling_odt_mpc=>ts_zml_ibooking WITH DEFAULT KEY.
    io_data_provider->read_entry_data( IMPORTING es_data = ls_travel_booking_data ).
    MOVE-CORRESPONDING ls_travel_booking_data TO ls_entity.
    ls_entity = zml_modify_travel( ls_entity = ls_entity ).
    MOVE-CORRESPONDING ls_travel_booking_data-to_booking TO ar_childentities.
    LOOP AT ar_childentities INTO ls_childentity.
      ls_childentity-travel_id = ls_entity-travel_id.
      ls_childentity = zml_modify_booking( ls_entity = ls_childentity ).
      ar_childentities[ sy-index ] = ls_childentity.
    ENDLOOP.
    MOVE-CORRESPONDING ls_entity TO es_s_trv_book.
    MOVE-CORRESPONDING ar_childentities TO es_s_trv_book-to_booking.
  ENDMETHOD.

 7-- Implementation of OData CRUD methods using override

7--1-- Start override methods

Open class `ZCL_ZML_TRAVELLING_ODT_DPC_EXT` (name of class is proposed during generating for overriding and the name of class is combination of by default:  `ZCL`_ + <name_of_service> + `_DPC_EXT`

This is generated class and will be regenerated if you need put changes in model and generate service once again.

SAP has classes for extending generated code, and those classes will not be re-created during generating, so your changes will be applicable after regenerating once again.

You can override any method by using Ctrl + space and choosing method for override from list:

lukcad_31-1714379019645.png

7--2-- override method `/iwbep/if_mgw_appl_srv_runtime~create_deep_entity` manually

This is single method which we do overriding manually and with definition in PUBLIC SECTION of class.

Add to PUBLIC SECTION this redefinition:

METHODS /iwbep/if_mgw_appl_srv_runtime~create_deep_entity REDEFINITION.

  Add to implementation area:

  METHOD /iwbep/if_mgw_appl_srv_runtime~create_deep_entity.
    DATA: ls_travel_booking_data TYPE zcl_zml_travelling_odt_mpc_ext=>ty_s_trv_book.
    CLEAR: er_deep_entity.
    TRY.
        CALL METHOD deep_insert_travel_booking
          EXPORTING
            io_data_provider = io_data_provider
          IMPORTING
            es_s_trv_book    = ls_travel_booking_data.
        copy_data_to_ref(
         EXPORTING
           is_data = ls_travel_booking_data
         CHANGING
           cr_data = er_deep_entity ).
      CATCH /iwbep/cx_mgw_busi_exception.
    ENDTRY.
  ENDMETHOD.

 7--3-- override method `zml_itravelset_update_entity`

  METHOD zml_itravelset_update_entity.
    DATA:
      ls_converted_keys TYPE zcl_zml_travelling_odt_mpc=>ts_zml_itravel,
      ls_entity         TYPE zcl_zml_travelling_odt_mpc=>ts_zml_itravel.
    io_data_provider->read_entry_data( IMPORTING es_data = ls_entity ).
    IF ( ls_entity-travel_id IS INITIAL ).
      io_tech_request_context->get_converted_keys(  IMPORTING es_key_values = ls_converted_keys ).
      ls_entity-travel_id = ls_converted_keys-travel_id.
    ENDIF.
    io_data_provider->read_entry_data( IMPORTING es_data = ls_entity ).
    CLEAR er_entity.
    er_entity = zml_modify_travel( ls_entity = ls_entity ).
  ENDMETHOD.

 7--4-- override method `zml_itravelset_delete_entity`

  METHOD zml_itravelset_delete_entity.
    DATA: ls_converted_keys TYPE zcl_zml_travelling_odt_mpc=>ts_zml_itravel.
    io_tech_request_context->get_converted_keys( IMPORTING es_key_values = ls_converted_keys ).
    DELETE FROM zml_booking WHERE travel_id = ls_converted_keys-travel_id.
    DELETE FROM zml_travel WHERE travel_id = ls_converted_keys-travel_id.
  ENDMETHOD.

 7--5-- override method `zml_itravelset_create_entity`

  METHOD zml_itravelset_create_entity.
    DATA: ls_entity TYPE zcl_zml_travelling_odt_mpc=>ts_zml_itravel.
    io_data_provider->read_entry_data( IMPORTING es_data = ls_entity ).
    CLEAR er_entity.
    er_entity = zml_modify_travel( ls_entity = ls_entity ).
  ENDMETHOD.

 7--6-- override method `zml_ibookingset_get_entity`

  METHOD zml_ibookingset_get_entity.
    DATA:ls_keytab TYPE LINE OF /iwbep/t_mgw_name_value_pair.
    LOOP AT it_key_tab INTO ls_keytab.
    ENDLOOP.
    IF ( ls_keytab-name = 'BookingId' ).
      SELECT SINGLE * FROM zml_booking INTO CORRESPONDING FIELDS OF er_entity WHERE booking_id = ls_keytab-value.
    ELSEIF ( ls_keytab-name = 'TravelId' ).
      SELECT SINGLE * FROM zml_booking INTO CORRESPONDING FIELDS OF er_entity WHERE travel_id = ls_keytab-value.
    ENDIF.
  ENDMETHOD.

 7--7-- override method `zml_itravelset_get_entity`

  METHOD zml_itravelset_get_entity.
    DATA:ls_keytab TYPE LINE OF /iwbep/t_mgw_name_value_pair.
    LOOP AT it_key_tab INTO ls_keytab.
    ENDLOOP.
    IF ( ls_keytab-name = 'BookingId' ).
      DATA: lv_travel_id TYPE zml_booking-travel_id.
      SELECT SINGLE travel_id FROM zml_booking INTO lv_travel_id WHERE booking_id = ls_keytab-value.
      IF sy-subrc = 0.
        SELECT SINGLE * FROM zml_travel INTO CORRESPONDING FIELDS OF er_entity WHERE travel_id = lv_travel_id.
      ENDIF.
    ELSEIF ( ls_keytab-name = 'TravelId' ).
      SELECT SINGLE * FROM zml_travel INTO CORRESPONDING FIELDS OF er_entity WHERE travel_id = ls_keytab-value.
    ENDIF.
  ENDMETHOD.

 7--8-- override method `zml_ibookingset_get_entityset`

  METHOD zml_ibookingset_get_entityset.
    DATA:ls_keytab TYPE LINE OF /iwbep/t_mgw_name_value_pair.
    LOOP AT it_key_tab INTO ls_keytab.
    ENDLOOP.
    IF ( ls_keytab IS NOT INITIAL ).
      IF ( ls_keytab-name = 'BookingId' ).
        SELECT * FROM zml_booking INTO CORRESPONDING FIELDS OF TABLE et_entityset WHERE booking_id = ls_keytab-value.
      ELSEIF ( ls_keytab-name = 'TravelId' ).
        DATA: lv_travel_id TYPE zml_travel-travel_id.
        SELECT SINGLE travel_id FROM zml_booking INTO lv_travel_id WHERE travel_id = ls_keytab-value.
        SELECT * FROM zml_booking INTO CORRESPONDING FIELDS OF TABLE et_entityset WHERE travel_id = lv_travel_id.
      ENDIF.
    ELSE.
      SELECT * FROM zml_booking INTO CORRESPONDING FIELDS OF TABLE et_entityset.
    ENDIF.
  ENDMETHOD.

 7--9-- override method `zml_itravelset_get_entityset`

  METHOD zml_itravelset_get_entityset.

    DATA: lv_source_entity_set_name TYPE /iwbep/mgw_tech_name.

    lv_source_entity_set_name = io_tech_request_context->get_source_entity_set_name( ).

    IF lv_source_entity_set_name IS INITIAL.

      SELECT * FROM zml_travel INTO CORRESPONDING FIELDS OF TABLE et_entityset.
    ELSE.
      SELECT * FROM zml_travel INTO CORRESPONDING FIELDS OF TABLE et_entityset.
    ENDIF.
  ENDMETHOD.

 7--10-- override method `zml_ibookingset_update_entity`

  method zml_ibookingset_update_entity.
    DATA:
      ls_converted_keys TYPE zcl_zml_travelling_odt_mpc=>ts_zml_ibooking,
      ls_entity         TYPE zcl_zml_travelling_odt_mpc=>ts_zml_ibooking.
    io_data_provider->read_entry_data( IMPORTING es_data = ls_entity ).
    IF ( ls_entity-booking_id IS INITIAL ).
      io_tech_request_context->get_converted_keys(  IMPORTING es_key_values = ls_converted_keys ).
      ls_entity-booking_id = ls_converted_keys-booking_id.
    ENDIF.
    io_data_provider->read_entry_data( IMPORTING es_data = ls_entity ).
    CLEAR er_entity.
    er_entity = zml_modify_booking( ls_entity = ls_entity ).
  endmethod.

 7--11-- override method `zml_ibookingset_delete_entity`

  method zml_ibookingset_delete_entity.
    DATA: ls_converted_keys TYPE zcl_zml_travelling_odt_mpc=>ts_zml_ibooking.
    io_tech_request_context->get_converted_keys( IMPORTING es_key_values = ls_converted_keys ).
    DELETE FROM zml_booking WHERE booking_id = ls_converted_keys-booking_id.
  endmethod.

7--12-- override method `zml_ibookingset_create_entity`

  method zml_ibookingset_create_entity.
    DATA: ls_entity TYPE zcl_zml_travelling_odt_mpc=>ts_zml_ibooking.
    io_data_provider->read_entry_data( IMPORTING es_data = ls_entity ).
    CLEAR er_entity.
    er_entity = zml_modify_booking( ls_entity = ls_entity ).
  endmethod.

 8-- Testing CRUD methods by SAP Gateway Client

8--1-- GET all records from entities

8--1--1-- GET entities with query parameter $format=json

Check again by SAP Gateway Client that you can extract data from ZML_ITRAVELSet and for ZML_IBOOKINGSet

/sap/opu/odata/sap/ZML_TRAVELLING_ODT_SRV/ZML_ITRAVELSet?$format=json

/sap/opu/odata/sap/ZML_TRAVELLING_ODT_SRV/ZML_IBOOKINGSet?$format=json

lukcad_32-1714379019646.png

lukcad_33-1714379019647.png

8--1--2-- GET entities by using header parameters instead of query parameter

You need to be able to add header parameters because in json it is easier to operate and some operation will work only with header (POST, PATCH, PUT and DELETE)

So look at screenshots below how you can add parameters and all rest screenshots will have always header parameters for your understanding.

lukcad_34-1714379019648.png

It is right to keep these two parameters added  for all operations:

lukcad_35-1714379019649.png

and add this parameter only for PATCH, PUT, and DELETE:

lukcad_36-1714379019649.png

8--2-- GET specific record from entity

lukcad_37-1714379019650.png

8--3-- GET specific record with details using EXPAND

lukcad_38-1714379019651.png

8--4-- PUT change record to change.

8--4--1-- PUT for ZML_ITRAVELSet it will be:

lukcad_39-1714379019652.png

8--4--2-- PUT for ZML_IBOOKINGSet it will be:

lukcad_40-1714379019653.png

You can verify if data were successfully applied by GET:

lukcad_41-1714379019654.png

8--6-- PATCH change only pointed parameters.

8--6--1-- PATCH for entity ZML_ITRAVELSet:

lukcad_42-1714379019655.png

8--6--2-- PATCH for entity ZML_IBOOKINGSet:

lukcad_43-1714379019656.png

You can verify if it was changes by GET:

lukcad_44-1714379019656.png

8--8-- DELETE -remove record and all child records

8--8--1-- DELETE for entity ZML_ITRAVELSet

Your code you can check and in code we delete child records from ZML_IBOOKINGSet and then record from ZML_ITRAVELSet. But it is up to you have this logic. You can allow delete only if childe records were delete previously. Just for simplicity we do deleting as cascade.

Notice: parameter `if-match` should be removed from header, overwise you will have error.

lukcad_45-1714379019657.png

8--8--2-- DELETE for entity ZML_IBOOKINGSet

Notice: parameter `if-match` should be removed from header, overwise you will have error.

lukcad_46-1714379019658.png

8--9-- INSERT - add new records

8--9--1-- INSERT for entity set `ZML_ITRAVELSet`

You have implemented `deep insert` with deep structure. So you expect to create complex records when you POST entity ZML_ITRAVELSet. It will be one record for ZML_ITRAVELSet and related records (child records) for entity ZML_IBOOKINGSet. Deep structure supposes to use head structure from ZML_ITRAVELSet and child structure with name `TO_BOOK` from ZML_IBOOKINGSet. So you have to prepare request with such payload:

{
  "Client" : "001",
  "Name" : "Travel Minsk - Milano",
  "TO_BOOKING": [
    {
        "Client" : "001",
        "Hotel" : "Ahmat hotel",
        "Dayfrom" : "\/Date(1481760000000)\/",
        "Dayto" : "\/Date(1481760000000)\/"
    },
    {
      "Client" : "001",
      "Hotel" : "Yes hotel",
      "Dayfrom" : "\/Date(1481760000000)\/",
      "Dayto" : "\/Date(1481760000000)\/"
    }
  ]
}

you point this URI:

/sap/opu/odata/SAP/ZML_TRAVELLING_ODT_SRV/ZML_ITRAVELSet

and you choose method: POST

lukcad_47-1714379019659.png

8--9--2-- INSERT for entity set `ZML_IBOOKINGSet`

You should know GUID of your parent record for ZML_ITRAVELSet

{
  "TravelId" : "0242ac11-0002-1eef-80aa-0315685dd657",
  "Hotel" : "Amirates Dubai stars",
  "Dayfrom" : "\/Date(1704067200000)\/",
  "Dayto" : "\/Date(1704326400000)\/"
}

lukcad_48-1714379019660.png

Response contains payload about what has been added and and which Booking Id was created.

If you wish you can GET particular record by using (guid' value of Booking Id ') :

lukcad_49-1714379019661.png

9-- Verification of achieved code

You can compare your code or if you feel that it is better to apply ready to use project and go through this document you can find this project here on GitHub:

https://github.com/lukcad/ZMLODATA.git

Also, you can verify your overridden methods for class zcl_zml_travelling_odt_dpc_ext here:

CLASS zcl_zml_travelling_odt_dpc_ext DEFINITION
  PUBLIC
  INHERITING FROM zcl_zml_travelling_odt_dpc
  CREATE PUBLIC .

  PUBLIC SECTION.


    METHODS /iwbep/if_mgw_appl_srv_runtime~create_deep_entity REDEFINITION.

  PROTECTED SECTION.
    methods zml_ibookingset_update_entity redefinition.
    methods zml_ibookingset_delete_entity redefinition.
    methods zml_ibookingset_create_entity redefinition.

    METHODS zml_create_uuid
      RETURNING VALUE(es_uuid) TYPE sysuuid_x16.

    METHODS zml_modify_travel
      IMPORTING
                !ls_entity       TYPE zcl_zml_travelling_odt_mpc=>ts_zml_itravel
      RETURNING VALUE(es_entity) TYPE zcl_zml_travelling_odt_mpc=>ts_zml_itravel.

    METHODS zml_modify_booking
      IMPORTING
                !ls_entity       TYPE zcl_zml_travelling_odt_mpc=>ts_zml_ibooking
      RETURNING VALUE(es_entity) TYPE zcl_zml_travelling_odt_mpc=>ts_zml_ibooking.

    METHODS deep_insert_travel_booking
      IMPORTING
        !io_data_provider TYPE REF TO /iwbep/if_mgw_entry_provider
      EXPORTING
        !es_s_trv_book    TYPE zcl_zml_travelling_odt_mpc_ext=>ty_s_trv_book
      RAISING
        /iwbep/cx_mgw_busi_exception
        /iwbep/cx_mgw_tech_exception .


    METHODS zml_itravelset_update_entity REDEFINITION.
    METHODS zml_itravelset_delete_entity REDEFINITION.
    METHODS zml_itravelset_create_entity REDEFINITION.
    METHODS zml_ibookingset_get_entity REDEFINITION.
    METHODS zml_itravelset_get_entity REDEFINITION.
    METHODS zml_ibookingset_get_entityset REDEFINITION.
    METHODS zml_itravelset_get_entityset REDEFINITION.

  PRIVATE SECTION.


ENDCLASS.



CLASS zcl_zml_travelling_odt_dpc_ext IMPLEMENTATION.

  METHOD zml_itravelset_get_entityset.

    DATA: lv_source_entity_set_name TYPE /iwbep/mgw_tech_name.

    lv_source_entity_set_name = io_tech_request_context->get_source_entity_set_name( ).

    IF lv_source_entity_set_name IS INITIAL.

      SELECT * FROM zml_travel INTO CORRESPONDING FIELDS OF TABLE et_entityset.
    ELSE.
      SELECT * FROM zml_travel INTO CORRESPONDING FIELDS OF TABLE et_entityset.
    ENDIF.
  ENDMETHOD.

  METHOD zml_ibookingset_get_entityset.
    DATA:ls_keytab TYPE LINE OF /iwbep/t_mgw_name_value_pair.
    LOOP AT it_key_tab INTO ls_keytab.
    ENDLOOP.
    IF ( ls_keytab IS NOT INITIAL ).
      IF ( ls_keytab-name = 'BookingId' ).
        SELECT * FROM zml_booking INTO CORRESPONDING FIELDS OF TABLE et_entityset WHERE booking_id = ls_keytab-value.
      ELSEIF ( ls_keytab-name = 'TravelId' ).
        DATA: lv_travel_id TYPE zml_travel-travel_id.
        SELECT SINGLE travel_id FROM zml_booking INTO lv_travel_id WHERE travel_id = ls_keytab-value.
        SELECT * FROM zml_booking INTO CORRESPONDING FIELDS OF TABLE et_entityset WHERE travel_id = lv_travel_id.
      ENDIF.
    ELSE.
      SELECT * FROM zml_booking INTO CORRESPONDING FIELDS OF TABLE et_entityset.
    ENDIF.
  ENDMETHOD.

  METHOD zml_itravelset_get_entity.
    DATA:ls_keytab TYPE LINE OF /iwbep/t_mgw_name_value_pair.
    LOOP AT it_key_tab INTO ls_keytab.
    ENDLOOP.
    IF ( ls_keytab-name = 'BookingId' ).
      DATA: lv_travel_id TYPE zml_booking-travel_id.
      SELECT SINGLE travel_id FROM zml_booking INTO lv_travel_id WHERE booking_id = ls_keytab-value.
      IF sy-subrc = 0.
        SELECT SINGLE * FROM zml_travel INTO CORRESPONDING FIELDS OF er_entity WHERE travel_id = lv_travel_id.
      ENDIF.
    ELSEIF ( ls_keytab-name = 'TravelId' ).
      SELECT SINGLE * FROM zml_travel INTO CORRESPONDING FIELDS OF er_entity WHERE travel_id = ls_keytab-value.
    ENDIF.
  ENDMETHOD.

  METHOD zml_ibookingset_get_entity.
    DATA:ls_keytab TYPE LINE OF /iwbep/t_mgw_name_value_pair.
    LOOP AT it_key_tab INTO ls_keytab.
    ENDLOOP.
    IF ( ls_keytab-name = 'BookingId' ).
      SELECT SINGLE * FROM zml_booking INTO CORRESPONDING FIELDS OF er_entity WHERE booking_id = ls_keytab-value.
    ELSEIF ( ls_keytab-name = 'TravelId' ).
      SELECT SINGLE * FROM zml_booking INTO CORRESPONDING FIELDS OF er_entity WHERE travel_id = ls_keytab-value.
    ENDIF.
  ENDMETHOD.

  METHOD zml_itravelset_create_entity.
    DATA: ls_entity TYPE zcl_zml_travelling_odt_mpc=>ts_zml_itravel.
    io_data_provider->read_entry_data( IMPORTING es_data = ls_entity ).
    CLEAR er_entity.
    er_entity = zml_modify_travel( ls_entity = ls_entity ).
  ENDMETHOD.

  method zml_ibookingset_create_entity.
    DATA: ls_entity TYPE zcl_zml_travelling_odt_mpc=>ts_zml_ibooking.
    io_data_provider->read_entry_data( IMPORTING es_data = ls_entity ).
    CLEAR er_entity.
    er_entity = zml_modify_booking( ls_entity = ls_entity ).
  endmethod.

  METHOD zml_itravelset_delete_entity.
    DATA: ls_converted_keys TYPE zcl_zml_travelling_odt_mpc=>ts_zml_itravel.
    io_tech_request_context->get_converted_keys( IMPORTING es_key_values = ls_converted_keys ).
    DELETE FROM zml_booking WHERE travel_id = ls_converted_keys-travel_id.
    DELETE FROM zml_travel WHERE travel_id = ls_converted_keys-travel_id.
  ENDMETHOD.

  method zml_ibookingset_delete_entity.
    DATA: ls_converted_keys TYPE zcl_zml_travelling_odt_mpc=>ts_zml_ibooking.
    io_tech_request_context->get_converted_keys( IMPORTING es_key_values = ls_converted_keys ).
    DELETE FROM zml_booking WHERE booking_id = ls_converted_keys-booking_id.
  endmethod.

  METHOD zml_itravelset_update_entity.
    DATA:
      ls_converted_keys TYPE zcl_zml_travelling_odt_mpc=>ts_zml_itravel,
      ls_entity         TYPE zcl_zml_travelling_odt_mpc=>ts_zml_itravel.
    io_data_provider->read_entry_data( IMPORTING es_data = ls_entity ).
    IF ( ls_entity-travel_id IS INITIAL ).
      io_tech_request_context->get_converted_keys(  IMPORTING es_key_values = ls_converted_keys ).
      ls_entity-travel_id = ls_converted_keys-travel_id.
    ENDIF.
    io_data_provider->read_entry_data( IMPORTING es_data = ls_entity ).
    CLEAR er_entity.
    er_entity = zml_modify_travel( ls_entity = ls_entity ).
  ENDMETHOD.

  method zml_ibookingset_update_entity.
    DATA:
      ls_converted_keys TYPE zcl_zml_travelling_odt_mpc=>ts_zml_ibooking,
      ls_entity         TYPE zcl_zml_travelling_odt_mpc=>ts_zml_ibooking.
    io_data_provider->read_entry_data( IMPORTING es_data = ls_entity ).
    IF ( ls_entity-booking_id IS INITIAL ).
      io_tech_request_context->get_converted_keys(  IMPORTING es_key_values = ls_converted_keys ).
      ls_entity-booking_id = ls_converted_keys-booking_id.
    ENDIF.
    io_data_provider->read_entry_data( IMPORTING es_data = ls_entity ).
    CLEAR er_entity.
    er_entity = zml_modify_booking( ls_entity = ls_entity ).
  endmethod.

  METHOD /iwbep/if_mgw_appl_srv_runtime~create_deep_entity.
    DATA: ls_travel_booking_data TYPE zcl_zml_travelling_odt_mpc_ext=>ty_s_trv_book.
    CLEAR: er_deep_entity.
    TRY.
        CALL METHOD deep_insert_travel_booking
          EXPORTING
            io_data_provider = io_data_provider
          IMPORTING
            es_s_trv_book    = ls_travel_booking_data.
        copy_data_to_ref(
         EXPORTING
           is_data = ls_travel_booking_data
         CHANGING
           cr_data = er_deep_entity ).
      CATCH /iwbep/cx_mgw_busi_exception.
    ENDTRY.
  ENDMETHOD.


  METHOD deep_insert_travel_booking.
    DATA: ls_travel_booking_data TYPE zcl_zml_travelling_odt_mpc_ext=>ty_s_trv_book.
    DATA: ls_entity TYPE zcl_zml_travelling_odt_mpc=>ts_zml_itravel.
    DATA: ls_childentity TYPE zcl_zml_travelling_odt_mpc=>ts_zml_ibooking.
    DATA: ar_childentities TYPE STANDARD TABLE OF zcl_zml_travelling_odt_mpc=>ts_zml_ibooking WITH DEFAULT KEY.
    io_data_provider->read_entry_data( IMPORTING es_data = ls_travel_booking_data ).
    MOVE-CORRESPONDING ls_travel_booking_data TO ls_entity.
    ls_entity = zml_modify_travel( ls_entity = ls_entity ).
    MOVE-CORRESPONDING ls_travel_booking_data-to_booking TO ar_childentities.
    LOOP AT ar_childentities INTO ls_childentity.
      ls_childentity-travel_id = ls_entity-travel_id.
      ls_childentity = zml_modify_booking( ls_entity = ls_childentity ).
      ar_childentities[ sy-index ] = ls_childentity.
    ENDLOOP.
    MOVE-CORRESPONDING ls_entity TO es_s_trv_book.
    MOVE-CORRESPONDING ar_childentities TO es_s_trv_book-to_booking.
  ENDMETHOD.

  METHOD zml_create_uuid.
    DATA lv_long_time_stamp TYPE timestampl.
    GET TIME STAMP FIELD lv_long_time_stamp.
    DATA: l_uuid_x16 TYPE sysuuid_x16.
    DATA: system_uuid TYPE REF TO if_system_uuid.
    DATA: oref        TYPE REF TO cx_uuid_error.
    system_uuid = cl_uuid_factory=>create_system_uuid( ).

    TRY.
        es_uuid = system_uuid->create_uuid_x16( ).
      CATCH cx_uuid_error.
        "handle exception
    ENDTRY.
  ENDMETHOD.

  METHOD zml_modify_travel.
    DATA:
      it_entity TYPE zcl_zml_travelling_odt_mpc=>ts_zml_itravel.
    MOVE-CORRESPONDING ls_entity TO it_entity.
    IF ( it_entity-client IS INITIAL ).
      it_entity-client = sy-mandt.
    ENDIF.
    TRY.
        it_entity-name = ls_entity-name.
        DATA itb_entity TYPE TABLE OF zml_travel.
        IF ( it_entity-travel_id IS INITIAL ).
          it_entity-travel_id = zml_create_uuid( ).
          itb_entity = VALUE #( ( it_entity )  ).
          INSERT zml_travel FROM TABLE @itb_entity.
        ELSE.
          itb_entity = VALUE #( ( it_entity )  ).
          MODIFY zml_travel FROM TABLE @itb_entity.
        ENDIF.
        es_entity = it_entity.
      CATCH cx_uuid_error.
    ENDTRY.
  ENDMETHOD.

  METHOD zml_modify_booking.
    DATA:
    it_entity TYPE zcl_zml_travelling_odt_mpc=>ts_zml_ibooking.
    MOVE-CORRESPONDING ls_entity TO it_entity.
    IF ( ls_entity-client IS INITIAL ).
      it_entity-client = sy-mandt.
    ENDIF.
    IF ( ls_entity-travel_id IS NOT INITIAL ).
      TRY.
          DATA itb_entity TYPE TABLE OF zml_booking.
          IF ( it_entity-booking_id IS INITIAL ).
            it_entity-booking_id = zml_create_uuid( ).
            itb_entity = VALUE #( ( it_entity )  ).
            INSERT zml_booking FROM TABLE @itb_entity.
          ELSE.
            itb_entity = VALUE #( ( it_entity )  ).
            MODIFY zml_booking FROM TABLE @itb_entity.
          ENDIF.
          es_entity = it_entity.
        CATCH cx_uuid_error.
      ENDTRY.
    ENDIF.

  ENDMETHOD.

ENDCLASS.

 

You can use this example of OData service as start point of developing your own package with own model and own project for OData by SEGW transaction. Now you have clear understanding how it can be implemented and fulfill business requirements, especially when those require none generative approach because particular changes of methods business consider as most effective approach on working production instances. 

Thank you for your attention and happy programming,

Yours sincerely,

Mikhail.

PS: if you missed this link: https://github.com/lukcad/ZMLODATA.git

 

2 Comments
Jelena
Active Contributor
0 Kudos

It's great that you've shared the code on GitHub and detailed steps using Eclipse.

This is a very old subject that has been written about extensively beginning from 2014 on SAP Community. Unfortunately, the new website makes it extremely difficult to search for the existing posts but here are some from the top of Google search.
https://community.sap.com/t5/technology-blogs-by-members/multi-deep-insert-in-sapgateway-segw-approa...

https://community.sap.com/t5/technology-blogs-by-members/step-by-step-development-for-create-deep-en...

https://community.sap.com/t5/technology-blogs-by-members/multi-deep-insert-in-sapgateway-segw-approa...

https://community.sap.com/t5/technology-blogs-by-members/step-by-step-procedure-for-create-deep-enti...

https://community.sap.com/t5/technology-blogs-by-members/steps-to-create-deep-insert-odata/ba-p/1334...

https://community.sap.com/t5/technology-blogs-by-members/easy-way-to-write-data-via-a-deep-entity-in...

https://community.sap.com/t5/technology-blogs-by-sap/how-to-implement-multi-level-create-deep/ba-p/1...

You can see most of them contain pretty much the same information. It's nice that your post also includes the data generation piece, although it would be logical to use the service itself to do that, no? What is missing in most posts and this one is the high-level explanation of why are you doing this, the overview of steps involved (and why), and pointing out the limitations of example (e.g. I see SELECT *, there is no way this will support full OData request range).

Most posts just go right into "start creating stuff". It's not wrong but I find it difficult to work with developers who just blindly learn "step by step" and have no idea what they're doing in general. Also again, a lot has been written about this already. At this point, I think it's reasonable to expect the posts not just repeating same steps but be more like "hey, I read these posts but X was not clear" or "I have a better example", etc. Thank you though at least for acknowledging this is an old approach. Some authors don't even do that.

lukcad
Explorer
0 Kudos

Dear community members!

Example on GitHub with this post both show how correctly expand methods and model by changing _EXT classes to implement custom CRUD and custom `deep insert`. Such topic is the most required in real projects and idea of this post was to help developers to use customization SAP SEGW with the right approach and also save time for understanding of implementation OData service by using a small simplified model and going through all steps of development to get results.

Yours sincerely,

Mikhail.

Labels in this area