Technology Blogs by Members
Explore a vibrant mix of technical expertise, industry insights, and tech buzz in member blogs covering SAP products, technology, and events. Get in the mix!
cancel
Showing results for 
Search instead for 
Did you mean: 
yavuzasik
Participant
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
Z_Cl_AMDP_PARSE_STRING=>SPLIT;

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.
  METHOD Z_DEMO_CDS_PARSE_WBS_GET_ENTITY_SET.
TRY.
CALL METHOD super->Z_DEMO_CDS_PARSE_WBS_GET_ENTITY_SET
EXPORTING
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
IMPORTING
et_entityset = et_entityset
es_response_context = es_response_context.
CATCH /iwbep/cx_mgw_busi_exception .
CATCH /iwbep/cx_mgw_tech_exception .
ENDTRY.

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

ENDLOOP.

ENDMETHOD.

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.


 
10 Comments
Jelena
Active Contributor
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!
Jan-WillemK
Active Participant
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
EXPORTING
it_select_options = it_filter_select_options
CHANGING
ct_data = et_entityset.

*** The module for $top and $skip Query Options
CALL METHOD /iwbep/cl_mgw_data_util=>paging
EXPORTING
is_paging = is_paging
CHANGING
ct_data = et_entityset.

*** The module for Orderby condition
CALL METHOD /iwbep/cl_mgw_data_util=>orderby
EXPORTING
it_order = it_order
CHANGING
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.
yavuzasik
Participant
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.
Michael_Keller
Active Contributor
Class /IWBEP/CL_MGW_DATA_UTIL is not a released object on SAP BTP 🙂
Jan-WillemK
Active Participant

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.

Jelena
Active Contributor
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!
Jelena
Active Contributor
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. 🙂
Jelena
Active Contributor
Because SAP wants us to use "massive layered CDS view", duh. 🙂
yavuzasik
Participant
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".

 
Jelena
Active Contributor
0 Kudos
Gotcha. Thank you for checking!
Labels in this area