Skip to Content
Technical Articles
Author's profile photo yavuz asik

Overcoming Technical and System Constraints: Exposing an ABAP Calculated Field with OData

Firstly, the requirement of this post was originated from quite a basic problem; however it later became really complicated due to the following constraints which we were restricted to.

  • technical constraints of ABAP CDS object
  • SAP system constraints in terms of the technology stack and version

Let me first talk about the actual requirement and then I will write down all the possible solutions I tried out and why I ended up with the current one. Our initial requirement was to expose an SAP field with OData and consume it from a Fiori application. This field was the well-known WBS element field, which is a concatenation of a couple of other fields separated by a ‘-‘ symbol. Of course, I was supposed to split this field into different strings and extract the components of the original field. It might sound like a problem with a quite straightforward solution. However once I started researching to find out the possibilities, it was quite frustrating.

Of course, I started with the CDS built-in functions. I have checked them and find out a couple of useful functions including “instr”, “substring”, “left” etc. However, none of them has completely resolved our problem without certain assumptions (making an assumption on the number of characters for each part of the string for instance). Therefore, unfortunately there is no built-in function, which we could utilize to split up a string into multiple strings at a certain character, ‘-‘ in our case.

Second option I came up with was to use some of the powerful tools in ABAP stack, for instance, CDS table function or AMDB, that I can plug our custom ABAP code. That way, I could enhance/enrich our CDS object with some custom ABAP coding, which contains the ABAP command SPLIT … AT … INTO …

@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Demo Table Function Parse'
@ClientDependent: false
define table function Z_DEMO_TF_PARSE_WBS
    returns {   
                wbs_element   : string40 ,
                component1    : string10  ,
                component2    : string10  ,	
                component3    : string10  ,					
                implemented by method

That way I planned to implement the parsing of the WBS string with custom Z_Cl_AMDP_PARSE_STRING class. Unfortunately, that also did not work out because our system had a SAP_ABA 750-0010 component version, which this feature is not yet supported.

The final option I could think of was to manually add an extra implementation into the OData runtime artifacts, which was generated by adding the CDS as a reference object to the SEGW service.

I did that extra implementation inside the data provider extension class. In order to implement the parsing of WBS field, I should have first created dummy fields in my CDS object, which was only possible with the CAST command. Hence, I extended my CDS view with the three field from the result of parsing.

@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@AbapCatalog.preserveKey: true
@EndUserText.label: 'Demo CDS Parse'
@VDM.viewType: #BASIC

define view Z_DEMO_CDS_PARSE_WBS as select from prps
     key wbs_element ,
     cast(' ' as abap.char(3) )  as component1  ,   
     cast(' ' as abap.char(10) ) as component2  ,     
     cast(' ' as abap.char(8) )  as component3        

Afterwards I started to overwrite some of the methods of the DPC_EXT class, which were necessary for my requirement. For instance I implemented the custom logic to split the WBS by overwriting the GET_ENTITYSET method of the respective CDS entity. This method already has a reference to the super method inherited from DPC class. Because the SEGW service was built on top of the reference to the data source which points to the CDS view. I preserved it and finally added my extra code to split the WBS element and hence the returned entity set is updated.

            iv_entity_name           = iv_entity_name
            iv_entity_set_name       = iv_entity_set_name
            iv_source_name           = iv_source_name
            it_filter_select_options = it_filter_select_options
            is_paging                = is_paging
            it_key_tab               = it_key_tab
            it_navigation_path       = it_navigation_path
            it_order                 = it_order
            iv_filter_string         = iv_filter_string
            iv_search_string         = iv_search_string
            io_tech_request_context  = io_tech_request_context
            et_entityset             = et_entityset
            es_response_context      = es_response_context.
      CATCH /iwbep/cx_mgw_busi_exception .
      CATCH /iwbep/cx_mgw_tech_exception .

    LOOP AT et_entityset REFERENCE INTO DATA(lr_entityset).
      SPLIT lr_entityset->wbs_element AT '-' INTO lr_entityset->component1



I want to emphasize a few points what I have learned from the solution of this issue.

  • Whenever CDS toolset is not adequate for my requirement , I can still use CDS to expose data by referencing it as data source and then exploit the DPC_EXT class to implement own coding. This makes it a hybrid solution whereas on one hand, I can take advantage of CDS features (performance, annotations etc.) and on the other hand, I can still make manual interventions to the entity set that I expose through OData by overwriting the related DPC_EXT class methods.
  • Second thing is that CAST operator is the only option to create dummy fields since CDS is not a database object but actually a view on real database objects. This could be its side role in addition to its actual role, which is casting some data types into some other types.


Assigned Tags

      You must be Logged on to comment or reply to a post.
      Author's profile photo Jelena Perfiljeva
      Jelena Perfiljeva

      Thanks for sharing and especially for explaining your thought process and specific limitations you had to work around.

      String functions in CDS are definitely not as strong as in ABAP, which is a bummer. I've also had a situation where SPLIT would work like a charm. Thankfully, we were able at least to use the table function, which was also your first idea.

      Looking at this CDS cheat sheet gave me an idea though of combining INSTR (which can find the position of a character in a string) with LEFT/RIGHT or SUBSTRING. In your case, you have multiple occurrences of '-', so it would need more than one "pass" probably. I found one blog post where a developer attempted exactly that and shared some options.I'm curious if this idea could work for your case too.

      As common with CDS, you might end up with layers upon layers of tiny CDS views. I really dislike that but the reason why I make every effort with CDS before resorting to SEGW is because CDS views support all OData queries with no additional code. Your code example would work in general but if you try doing top/skip/filter, etc. you either have to code all those manually or end up with incorrect results. (If you consciously don't want to implement these queries, it might be a good idea then to raise an exception to say it's not supported.)

      Thanks again!

      Author's profile photo Jan-Willem Kaagman
      Jan-Willem Kaagman

      Hi Jelena,

      If your result set is not too long, you can use a standard solution for the $top, $filter, etc :

      *** The module for Filter conditions 
           CALL METHOD /iwbep/cl_mgw_data_util=>filtering 
               it_select_options = it_filter_select_options 
               ct_data           = et_entityset. 
      *** The module for $top and $skip Query Options 
           CALL METHOD /iwbep/cl_mgw_data_util=>paging 
               is_paging = is_paging 
               ct_data   = et_entityset. 
      *** The module for Orderby condition 
           CALL METHOD /iwbep/cl_mgw_data_util=>orderby 
               it_order = it_order 
               ct_data  = et_entityset. 

      As this is relatively easy to implement, I prefer this to a massive layered CDS view, especially if you're not on a HANA database yet.

      Author's profile photo Michael Keller
      Michael Keller

      Class /IWBEP/CL_MGW_DATA_UTIL is not a released object on SAP BTP 🙂

      Author's profile photo Jan-Willem Kaagman
      Jan-Willem Kaagman

      That's a pity! It is really a nifty class. I wonder why it is not released? I have seen this class being used in standard SAP software, and even in some older SAP documentation or course or something such.
      Luckily Yavuz pointed out that he is working on a SAP_ABA 750 system, so he will be able to use these classes.

      Author's profile photo Jelena Perfiljeva
      Jelena Perfiljeva

      Because SAP wants us to use "massive layered CDS view", duh. 🙂

      Author's profile photo Jelena Perfiljeva
      Jelena Perfiljeva

      I'm aware of paging/sort but I've not tried that filtering method tbh because all my use cases were not straightforward. When say, your dataset contains a true/false indicator and you need to do some interpretation (e.g. "is this order open?"), then it gets more complicated really quick.

      It's also different ballgame altogether before HANA. Sometimes non-obvious stuff for performance reasons. Fun times. 🙂

      Author's profile photo yavuz asik
      yavuz asik
      Blog Post Author

      Hi Jelena,

      Thanks for the comment.

      Indeed I tried to resolve the issue with CDS String operations in the first hand. Maybe I could not explain it very well in the post. The thing is that I had dynamic-length fields as compared to the post you shared. In my case for instance, the second field in the structure was "customer code" field which has a varying length between 2-20 characters. In that case I could not combine the string commands dynamically.

      For the OData query part, I have omitted the operations code in the post. Actually I had to add the top/skip/filter code manually. Nevertheless the CDS selection part, which contains some other fields I haven't mentioned in the post, was handled by the framework. That was also useful for the performance.

      Author's profile photo Jelena Perfiljeva
      Jelena Perfiljeva

      I understood you correctly that you can't use LEFT/RIGHT because you don't know the length of substring. It's not what I was suggesting.

      My thought was that if, for example, you have values like 11-2222 or 1111-2222 then first, you use INSTR to find where the dash is located. It would be position 3 and 5 in these examples. That allows you to use that value (+/- 1) in LEFT/RIGHT operations. It adds quite a bit of complexity though which is usually not good. But I was curious if you considered that option. It sounds like no.

      Thanks for a response!

      Author's profile photo yavuz asik
      yavuz asik
      Blog Post Author

      Hi Jelena,

      As far as I can recollect, I could only use literals with LEFT,RIGHT operators.

      Indeed, I just tried out and the compiler says: "Function LEFT: at position 2, only literals, possibly positive integers allowed".


      Author's profile photo Jelena Perfiljeva
      Jelena Perfiljeva

      Gotcha. Thank you for checking!