Skip to Content
Author's profile photo Uladzimir Sapazhkou

C-create, R-read, U-update, D-delete OData Services Creation Using ABAP CDS Views

Introduction

This article describes the fastest way of OData Services creation using ABAP Core Data Services. Details on @OData.publish annotation utilization, reference to Data Source CDS-Entity and import from DDIC Structure are given. Create, Update and Delete actions are shown on the custom transparent table data just to simplify the article and do not move focus from OData Service creation to business process requirements implementation.

 

“R” Type OData Service Creation. With using of @OData.publish annotation in ABAP CDS

Let us assume that we have any data table (probably in the custom namespace, just to simplify the demo case and get focused on OData service only, and not on SAP functional modules and class usage)

It is possible to create ABAP CDS view for it using SAP HANA Studio

During CDS activation OData service will be generated in the background

Service document looks like this:

 

“R” Type OData Service Creation. Using reference on ABAP CDS

Let us assume that we have any data table (probably in custom namespace, just to simplify demo case and get focused on OData service only, and not on SAP functional modules and class usage)

It is possible to create ABAP CDS view for it using SAP HANA Studio. Please consider that in this case there is no @OData annotation in use

During our next step we will Create Gateway Project via transaction code SEGW and refer it to the created in the previous step ABAP CDS

SAP will generate runtime objects based on reference to ABAP CDS

The service document looks like this:

 

“CRUD” Type OData Service Creation

Let us assume that we have any data table (probably in custom namespace, just to simplify the demo case and get focused on OData service only, and not on SAP functional modules and class usage)

It is possible to create ABAP CDS view for it using SAP HANA Studio (no @OData annotation is in use)

During our next step we will Create Gateway Project via transaction code SEGW and import DDIC Structure (use @AbapCatalog.sqlViewName value from ABAP CDS, please see the picture above)

If you are using complex CDS with associations (for Master-Details view, for example) you should additionally create Associations and Navigation Properties. This section will be added.

SAP will generate runtime objects

For “CRUD” type of OData Services we should set parameters of Entity Set and then implement each of them

Navigate to ABAP Workbench and redefine methods of *DPC_EXT class for CRUD operations

Here it is possible to point out SELECT statement directly to ABAP CDS for Get_EntitySet method

  METHOD experimentset_get_entityset.
     SELECT * 
       FROM zxeq1_lexprmnt01
       INTO CORRESPONDING FIELDS OF TABLE @et_entityset 
       ORDER BY PRIMARY KEY.
   ENDMETHOD.

If you set Searchable parameter of Entity Set then ABAP code implementation should look like the following

  METHOD experimentset_get_entityset.
     DATA: lv_osql_where_clause TYPE string. 
     "Prepare where clause
     lv_osql_where_clause = io_tech_request_context->get_osql_where_clause( ). 
     "Select data
     SELECT * 
       FROM zxeq1_lexprmnt01
       INTO CORRESPONDING FIELDS OF TABLE @et_entityset
       WHERE (lv_osql_where_clause) 
       ORDER BY PRIMARY KEY.
   ENDMETHOD.

If you additionally set Pageable parameter of Entity Set then ABAP code should look like the following

  METHOD experimentset_get_entityset.
     DATA: lv_osql_where_clause TYPE string,
           lv_top               TYPE i,
           lv_skip              TYPE i,
           lv_max_index         TYPE i.
     "Prepare top and skip
     lv_top = io_tech_request_context->get_top( ).
     lv_skip = io_tech_request_context->get_skip( ).
     IF lv_top IS NOT INITIAL.
       lv_max_index = lv_top + lv_skip.
     ENDIF.
     "Prepare where clause
     lv_osql_where_clause = io_tech_request_context->get_osql_where_clause( ).
     "Select data
     SELECT *
       FROM zxeq1_lexprmnt01
       INTO CORRESPONDING FIELDS OF TABLE @et_entityset
       UP TO @lv_max_index ROWS
       WHERE (lv_osql_where_clause)
       ORDER BY PRIMARY KEY.
     "Process skip
     IF lv_skip IS NOT INITIAL.
       DELETE et_entityset TO lv_skip.
     ENDIF. 
     "Process inline couter
     IF io_tech_request_context->has_inlinecount( ) = abap_true.
       SELECT COUNT(*)
         FROM zxeq1_lexprmnt01 WHERE (lv_osql_where_clause).
       es_response_context-inlinecount = sy-dbcnt.
     ELSE.
       CLEAR es_response_context-inlinecount.
     ENDIF.
   ENDMETHOD.

In Get_Entity method we should use ABAP CDS and other data type related objects and key field names

  METHOD experimentset_get_entity.
     DATA: ls_data       TYPE zcl_xeq1s_exprmnt01p_mpc=>ts_experiment.
     "Convert keys to data
     CALL METHOD io_tech_request_context->get_converted_keys
       IMPORTING
         es_key_values = ls_data.
     "Select data by keys
     SELECT SINGLE *
       INTO CORRESPONDING FIELDS OF @er_entity
       FROM zxeq1_lexprmnt01
       WHERE uname = @ls_data-uname.
   ENDMETHOD.

If you set Creatable parameter of Entity Set then you should implement Create_Entity method and ABAP code could look like the following. In our current example we are using database table as target to INSERT data (in more complex and realistic business case SAP BAPI or functional modules or ABAP Classes should be used here to implement required business logic)

  METHOD experimentset_create_entity.
     DATA: ls_data       TYPE zxeq1_dexprmnt01.
     "Insert data in database
     MOVE-CORRESPONDING er_entity TO ls_data.
     INSERT zxeq1_dexprmnt01
       FROM @ls_data.
   ENDMETHOD.

If you set Updatable parameter of Entity Set then you should implement Update_Entity method like the following sample. In our current example we are using database table as target to UPDATE data (in more complex and realistic business case SAP BAPI or functional modules or ABAP Classes should be used here to implement required business logic)

  METHOD experimentset_update_entity.
     DATA: ls_data       TYPE zxeq1_dexprmnt01.
     "Update data in database
     MOVE-CORRESPONDING er_entity TO ls_data.
     UPDATE zxeq1_dexprmnt01
       FROM @ls_data.
   ENDMETHOD.

If you set Deletable parameter of Entity Set then you should implement Delete_Entity method like the following sample. In our current example we are using database table as target to DELETE data (in more complex and realistic business case SAP BAPI or functional modules or ABAP Classes should be used here to implement required business logic)

  METHOD experimentset_delete_entity.
     DATA: ls_data       TYPE zcl_xeq1s_exprmnt01p_mpc=>ts_experiment.
     "Convert keys to data
     CALL METHOD io_tech_request_context->get_converted_keys
       IMPORTING
         es_key_values = ls_data.
     "Delete data from database
     DELETE FROM zxeq1_dexprmnt01
       WHERE uname = @ls_data-uname.
   ENDMETHOD.

As a result, there is the following OData Service Document created

 

 

Conclusion

This article shows a fast and simple way of OData Service creation with full CRUD functions support based on ABAP CDS technology. It is possible to see that wrapper for CRUD OData Service based on ABAP CDS could be created as fast as a few hours activity. What is needed is simply to add ABAP logic inside it that is mostly the same kind of activities we’ve done in ABAP development before web services usage. Additionally, OData Service created on ABAP CDS views is ready to be consumed by SAP HTML5 (UI5) Application and could either be deployed to your company local SAP Fiori Launchpad or to SAP Fiori Cloud Launchpad (Portal) from SAP Cloud Platform.

P.S. Please consider that in case of SAP Fiori Cloud Launchpad usage we have to wrap OData Service using SAP Cloud Platform OData Provisioning Service (that is covered in another article).

Assigned Tags

      21 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Mahesh Palavalli
      Mahesh Palavalli

      Hi Uladzimir,

      Nice Blog. There is one more way, where you can directly bind the CDS view to the entity. So we dont need to write the code to fetch the data. SADL layer will fetch the data for us with top, skip, filters.., applied automatically.

      In the service implementation, right click on the entity and map to data source, here map the same to CDS view.

       

      Thanks & Best Regards,

      Mahesh

      Author's profile photo Uladzimir Sapazhkou
      Uladzimir Sapazhkou
      Blog Post Author

      Hi Mahesh Palavalli,

      Thank you for useful information!

      Author's profile photo Zubair D3 squad
      Zubair D3 squad

      Thanks mahesh.

      Author's profile photo Deborshi De Sarkar
      Deborshi De Sarkar

      Hello, Mahesh Palavalli,

      Which is the other way we can directly bind CDS view to the entity?

      Author's profile photo Mahesh Palavalli
      Mahesh Palavalli
       Deborshi De Sarkaryou need to do the sadl mapping, import the cds view as entity types in the odata project and go to entity set and map it to the cds view. right click on the entityset you will get the option.
      Author's profile photo Deborshi De Sarkar
      Deborshi De Sarkar

      Hi Mahesh Palavalli   Is this BOPF  ?

      Author's profile photo Mahesh Palavalli
      Mahesh Palavalli

      No, it is'nt.. it's just normal mapping of cds view to the entity set.. You can even map a database table or view..

      Author's profile photo Sarbjeet Singh
      Sarbjeet Singh

      Hey Mahesh,

      Is there any way to pass on the CDS UI annotations automatically using this mapping editor method?

       

      Regards,

      Sarbjeet Singh

      Author's profile photo Mahesh Palavalli
      Mahesh Palavalli

      Hi Sarbjeet Singh

      I don't think it is possible if we do like that. I've only observed the annotations flowing from the Odata service that is generated from the CDS view or via the referenced odata source.

      BR,

      Mahesh

      Author's profile photo Sarbjeet Singh
      Sarbjeet Singh

      Thanks.

      Author's profile photo Thomas Mundt
      Thomas Mundt

      Hi @Mahesh Kumar Palavalli

      Is it possible to redefine methods for CDS, to apply addational data/logic not being covered by CDS?

      I try to call method to include more data in entity while GET request is initiated for the entity.

      Your help is much appreciated!

      Thomas

      Author's profile photo Mahesh Palavalli
      Mahesh Palavalli

      If the service is not generated from the CDS view then yes it is possible as you will be doing it via the reference odata source or entity set binding to individual cds view.

      So in the dpc_ext class, redefine the required enitityset method and call the super class method again so that the SADL layer will take care of the actual read then after that manipulate the response.

      is that what you are expecting?

      Author's profile photo Thomas Mundt
      Thomas Mundt

      Yes I do. You confirmed something I only could guess about. Thank you very much for your valuable response!

      Is it possible to access data from a database table of another system in this method? What I need to achieve is to fetch data from another odata service and its entity.

      Author's profile photo Thomas Mundt
      Thomas Mundt

      FYI:
      I skipped data retrieval on the ABAP/backend side. My solution is to the stuff on frontend, accessing two different OData services.

      Author's profile photo Che Eky
      Che Eky

      Hi @Mahesh Palavalli,

      Say the OData is generated via the reference odata source and the CDS contains aggregation annotation. If you manipulate the response in the dpc_ext class could it affect the guid generated for aggregation? or is the aggregation and guid generated after manipulating the response in the dpc_ext class?

      Author's profile photo Che Eky
      Che Eky

      I tested this and the aggregation has already been done by the time the data is available in the redefined get_entityset. So you cannot add or filter out rows of data as it will invalidate the totals. What you can do is calculate additional fields for display that will not affect the totals, e.g. fetch a text, etc. Because of pagination only a subset of data is available in the get_entityset, not all. This has the benefit that you can perform calculations on a subset of data which should be faster than the whole dataset.

      Author's profile photo Bodhisattwa Pal
      Bodhisattwa Pal

      Hi  Mahesh

      Thanks for raising this topic .

      I was under the impression that SADL technique can be used only for fetching data .Not for making any modification (Update , Delete ) .

      Could you kindly share any article how to make modifications  in a CDS view , using SADL .

      The only two options I am aware of  , for making modifications (Update , Delete )  are BOPF and the one mentioned by   @Uladzimir .

      Thanks

      Bodhisattwa Pal

       

       

       

      Author's profile photo Mahesh Palavalli
      Mahesh Palavalli

      I think those are the only ways with CDS views.

      1. Reference data source/cds data source for entity & manually overriding the crud methods
      2. abap programming model for fiori & usng bopf
      3. ABAP RAP
      Author's profile photo Muthukumaran Pandian
      Muthukumaran Pandian

      Thanks Mahesh.

      Author's profile photo Idris Ahmed Khan
      Idris Ahmed Khan

      Hi Uladzimir,

       

      Thanks for the great document.

      I tried to implement the above-explained method. will it only work for the custom dictionary object because in delete method you mentioned to delete it specifically?

      I have a requirement to use standard I_MaterialStock view and it is required to remove or hide a field in Fiori query browser, can we achieve delete fields for standard views using the above method?

      we have a requirement to hide/remove a certain field from standard view "C_MaterialStockActual". is there any other method to hide fields in a fiory application?

       

      Regards,

      Idris.

       

       

      Author's profile photo Jayanta Choudhuri
      Jayanta Choudhuri

      Uladzimir should have kept the 3 scenarios with unqiue names
      ZXEQ2S_LEXPRMNT02 ZXEQ3S_LEXPRMNT03

      experimentset_create_entity and experimentset_update_entity are both wrong
      These result in NULL rows ie. spaces and zeroes; ABAP lingo initial

      I could not get a good SAP Blog
      But stepped out to https://www.zapyard.com/odata-and-sap-netweaver-gateway-part-v-crud-operations-in-odata-services/
      Good vetted samples also in few other sites

        method ENTITY03SET_CREATE_ENTITY.
      **TRY.
      *CALL METHOD SUPER->ENTITY03SET_CREATE_ENTITY
      *  EXPORTING
      *    IV_ENTITY_NAME          =
      *    IV_ENTITY_SET_NAME      =
      *    IV_SOURCE_NAME          =
      *    IT_KEY_TAB              =
      **    io_tech_request_context =
      *    IT_NAVIGATION_PATH      =
      **    io_data_provider        =
      **  IMPORTING
      **    er_entity               =
      *    .
      **  CATCH /iwbep/cx_mgw_busi_exception.
      **  CATCH /iwbep/cx_mgw_tech_exception.
      **ENDTRY.
           DATA: ls_data       TYPE ZCL_ZXEQ3S_LEXPRMNT03_MPC=>TS_ENTITY03. "TYPE zxeq1_dexprmnt01.
           io_data_provider->read_entry_data( IMPORTING es_data = ls_data ).
           ls_data-mandt = sy-mandt.
           "Insert data in database
           "MOVE-CORRESPONDING er_entity TO ls_data.
           er_entity = ls_data.
           INSERT zxeq1_dexprmnt01
             FROM @ls_data.
        endmethod.
      METHOD ENTITY03SET_UPDATE_ENTITY.
      **TRY.
      *CALL METHOD SUPER->ENTITY03SET_UPDATE_ENTITY
      *  EXPORTING
      *    IV_ENTITY_NAME          =
      *    IV_ENTITY_SET_NAME      =
      *    IV_SOURCE_NAME          =
      *    IT_KEY_TAB              =
      **    io_tech_request_context =
      *    IT_NAVIGATION_PATH      =
      **    io_data_provider        =
      **  IMPORTING
      **    er_entity               =
      *    .
      **  CATCH /iwbep/cx_mgw_busi_exception.
      **  CATCH /iwbep/cx_mgw_tech_exception.
      **ENDTRY.
      
        DATA: ls_data       TYPE ZCL_ZXEQ3S_LEXPRMNT03_MPC=>TS_ENTITY03. "TYPE zxeq1_dexprmnt01.
        DATA: ls_keys       TYPE ZCL_ZXEQ3S_LEXPRMNT03_MPC=>TS_ENTITY03.
        DATA: ls_message    TYPE scx_t100key.
      
        CALL METHOD io_tech_request_context->get_converted_keys
        IMPORTING
          es_key_values = ls_keys.
      
        " determine value of node_key.
        SELECT SINGLE * FROM zxeq1_dexprmnt01
        WHERE uname = @ls_keys-uname
        INTO @ls_data.
      
        " add check whether product exist or not
        IF sy-subrc <> 0.
          " implement suitable error handling here
          ls_message-msgid = 'SY'.
          ls_message-msgno = '002'.
          CONCATENATE 'Update for ' ls_keys-uname ' failed' INTO ls_message-attr1.
      
          RAISE exception TYPE /iwbep/cx_mgw_busi_exception
          EXPORTING
            textid = ls_message.
        ENDIF.
      
        io_data_provider->read_entry_data( IMPORTING es_data = ls_data ).
        ls_data-mandt = sy-mandt.
        "Insert data in database
        "MOVE-CORRESPONDING er_entity TO ls_data.
        er_entity = ls_data.
      
        "Update data in database
        UPDATE zxeq1_dexprmnt01
        FROM @ls_data.
        " ERROR CHECK LOCKING Omitted
      ENDMETHOD.

      CREATE_ENTITY shadowed on zapyard is a happy ending
      UPDATE_ENTITY does the job but returns
      ~status_code 204
      ~status_reason No Content

      DELETE_ENTITY has the right code

           CALL METHOD io_tech_request_context->get_converted_keys
             IMPORTING
               es_key_values = ls_data.

      Oversight in CREATE_ENTITY and UPDATE_ENTITY is probably author assuming that reader has the experience

      I am new in the latest ABAP developments so was delayed!

      Overall the blog was very useful to me

      Mahesh Palavalli comment would be best explained with a concrete vetted example of "mapped datasource"

      Andre Fischer has great blogs and recommends RAP(I am clueles)
      and CDS with BOPF for CUD

       

      @OData.publish: true //To Make it BOPF Enabled
      @ObjectModel:{semanticKey: 'AirlineCode',
      //This will Delegate the CRUD to Transactional CDS
      transactionalProcessingDelegated: true,
      //To define what all actions are enabled
      createEnabled: true, deleteEnabled: true, updateEnabled: true }

      As used by Amit Diwane in
      https://blogs.sap.com/2020/06/26/sap-abap-programming-model-for-fiori-list-report-application-part-1/comment-page-1

      Happy ending apart for UPDATE_ENTITY
      By doubts how to avoid key update
      how to update only the input content selected fields?

      Regards
      Jayanta@Kolkata

      For perfect solution with optimistic locking (by Andre Fischer)
      https://blogs.sap.com/2017/05/05/how-to-handle-etags-in-sap-gateway-using-code-based-implementation/

      PDF by Andre Fischer on the many options https://assets.cdn.sap.com/sapcom/docs/2019/07/28ed1f77-587d-0010-87a3-c30de2ffd8ff.pdf

      Could not find any reliable BOPF DRAFT based Fiori Odata example