Skip to Content
Technical Articles

Access Gateway exposed CDS within the ABAP stack itself: OData.publish

Introduction

In my previous blog https://blogs.sap.com/2020/02/12/access-gateway-exposed-cds-within-the-abap-stack-itself/ I discussed the situation that you make use of Gateway exposed CDS views in an ABAP system, but have to maintain these views from that very same ABAP system – for batch purposes or the likes. I described a way working with CDS views in mind that were explicitly referenced in SEGW projects.

One of the questions that popped up in the reactions was how to deal with this approach if you want to use direct expose from the CDS view with the annotation @OData.publish is true. I took the challenge to discover that it appeared to be even simpler.

For those who have not read my previous post, we are talking about ABAP CDS views on a Hana Database,

  • with ObjectModel.modelCategory is #BUSINESS_OBJECT
  • with ObjectModel.writeActivePersistency set to a database table
  • with ObjectModel.createEnabled (updateEnabled, deleteEnabled) set to true, so with updating logic in mind
  • We wish full CRUD access to the database, through BOBF, from the same ABAP system.

Contrary to my previous blog, now annotation OData.publish is set to true.

Context

We have a simple transparent client dependent table created called ZZHP_SADL_TEST, with key ID and field value1. Then I have created a CDS view for this table.

@AbapCatalog.sqlViewName: 'ZZHPSADLL2'
@AbapCatalog.compiler.compareFilter: true
@AbapCatalog.preserveKey: true
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'ZZHP_SADL_L2'

@ObjectModel.semanticKey: 'Supplier'
@ObjectModel.modelCategory: #BUSINESS_OBJECT 
@ObjectModel.compositionRoot: true  
@ObjectModel.transactionalProcessingEnabled: true  
@ObjectModel.writeActivePersistence: 'ZZHP_SADL_TEST'
        
@ObjectModel.createEnabled: true
@ObjectModel.deleteEnabled: true 
@ObjectModel.updateEnabled: true

@OData.publish: true

define view ZZHP_SADL_L2 as select from zzhp_sadl_test {
  key id as id,
  value1 as value1  
}

When activation this view you will see a gray dot in the ruler just before the annotation @Odata.publish, indicating that something is generated here. There are many blogs to be found on this subject so I leave that and service activation out of scope. Interesting for this blog is that besides the BOBF object with the name of the view, also an MPC exposure class is generated (ZCL_{VIEWNAME}. With that class we can utilize the SADL runtime quite easily.

Bring the action back to ABAP: Read

Now getting this back to ABAP here is a pleasant surprise. Where with @Odata.publish set false we had to get back to the implementation of the Gateway project, Now we can fully rely on a class generated by the framework. As a consequence we even don’t even need to make subclasses for the SADL entity mapper and the SALD transaction manager!

Except however for the condition class, which I will only mention her and would like to refer to my previous blog on this subject (access-gateway-exposed-cds-within-the-abap-stack-itself). Here is the complete snippet for the read. Again, Plain ABAP report, no includes, andĀ  the register for the condition provider grayed out only to show where it should placed.

start-of-selection.
  try.
      data(lr_bobobj) = new zcl_zzhp_sadl_l2( ).
      data(lr_iomp)   = lr_bobobj->if_sadl_gtk_generic_mpc~get_sadl_mp( ).
      data(lr_sapi)   = cl_sadl_entity_api_factory=>create( cast #( lr_iomp ) ).
      data(lr_runt)   = lr_sapi->get_runtime( 'ZZHP_SADL_L2' ).

*     lr_runt->if_sadl_query_fetch~register_condition_provider( ... )

      " Set scope for selected fields (from CDS view), and flag data to be fetched
      data ls_parameters type if_sadl_query_engine_types=>ty_requested.
      ls_parameters-fill_data = abap_true.
      append:
        'ID'             to ls_parameters-elements,
        'VALUE1'         to ls_parameters-elements.

      data lt_data type table of zzhp_sadl_l2.

      lr_runt->fetch(
        exporting
          is_requested = ls_parameters

        importing
          et_data_rows = lt_data
      ).

    catch cx_root into data(lx).
      " any error handling
  endtry.

So the things we need to know here are:

  • The name of the view, in this case ZZHP_SALD_L2
  • The name of the generated MPC access class, in this case ZCL_ZZHP_SADL_L2
  • And of course the structure of the view you want to read.

And yes, the basic access to the runtime requires only fourĀ  lines of code.

Bring the action back to ABAP: Update

Updating is as just as simple. Let’s look at the snippet:

start-of-selection.
  try.
      data(lr_bobobj) = new zcl_zzhp_sadl_l2( ).
      data(lr_iomp)   = lr_bobobj->if_sadl_gtk_generic_mpc~get_sadl_mp( ).
      data(lr_sapi)   = cl_sadl_entity_api_factory=>create( cast #( lr_iomp ) ).
      data(lr_runt)   = lr_sapi->get_runtime( 'ZZHP_SADL_L2' ).

      data ls_data type zzhp_sadl_l2.
      ls_data-id     = '23344'.
      ls_data-value1 = 'Time for a good cup of tea'.

      lr_runt->if_sadl_entity_transactional~create_single(
        importing
          ev_failed = data(lv_updatefailed)
        changing
          cs_entity_data = ls_data
      ).

      data(lr_trans_man) = cl_sadl_transact_manager_fctr=>get_transaction_manager( ).

      if lv_updatefailed = abap_false.
        lv_updatefailed = lr_trans_man->save( ). " Commit the changes
      else.
        lr_trans_man->discard_changes( ).
      endif.

      if lv_updatefailed eq abap_true.
        lr_trans_man->get_message_handler( )->get_messages( 
           ...   "TODO proper error handling 
           ... 
      endif.
    catch cx_root into data(lx).
      " TO DO Exception handling 
  endtry.

In this case we considered a post, but in exact the same manner as described in my previous blog (access-gateway-exposed-cds-within-the-abap-stack-itself) you can implement (multi-) post, (multi-) update and (multi-) delete.

Final thoughts

In the previous blog I had some thoughts about the way of implementation. Explicitly that you had to be aware of an internal format {SERVICE} ~ {ENTITY}, of the creation of a few subclasses. I cannot find one of these issues here. It all looks pretty straight forward and more standard. So from that point of view I must favor the way with OData.publish set to true.

I look forward to any comments of suggestions.

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