Skip to Content
Technical Articles
Author's profile photo Ramjee Korada

ABAP RAP : Side Effects in CDS Behavior Definition and its variants

​​​
Introduction:
 
​The most awaited feature was released for SAP BTP – ABAPEnvironment in 2302. It is none other than ‘Side effects in CDS Behavior Definition’.

I have been waiting for this feature and can’t stop myself from trying it. I thought the syntax would be complicated and was surprised when I realized they were so simple and readable.

​Side effects are useful in UI scenarios based on draft-enabled BOs to notify a Fiori Elements UI that data changes of defined fields require the recalculation of other data values, permissions or messages  .​

Earlier we had to use annotations in Fiori Application to refresh the target elements on the UI automatically. Th​is​ new features reduce the dependency on UI development and help backend developers to test functions in ADT preview itself. 

Multiple variants are already available and t​his blog post describes most used cases and other features are yet to be explored. 

  1. Side effects in the same entity on field change
  2. Side effects in different entities on a field change
  3. Side effects in different entities on a custom action.
T​o demonstrate and focus on this feature, a well-known travel data model with booking as a composition child and OData v4 + Draft is considered . 
Use case: 
In this example, Travel is the root entity and Booking as a composition ​child. Total price on travel entity is a read only field and it is the summation of Booking-fee on ​Travel entity and Flight-Price from each Booking entity. 
That means Total-Price needs to be updated whenever 
  • booking-fee is changed or 
  • new booking is created or 
  • Flight price is changed. 
To complicate things a little, let us introduce a custom action to apply discounts on selective flight bookings. So that flight prices are recalculated and also Total price on Travel is also calculated and reflected on UI.
Implementation approach: 
  1. ​Develop the Fiori elements application using RAP-CDS-Modeling. ​
  2. ​Define the required determinations and actions on the specified entities.
  3. ​Implement the business logic in ​respective Behavior Pool classes
  4. Identify the source properties and target properties/entities for side effects
  5. Define the side effects in Behavior definition ( note: Only once side effects can be defined in a behavior definition )
  6. ​Expose the side​ effects in Projection level behavior definition so that they are available UI consumption.
I​mp​lementation steps: 

  1. ​Develop the fiori elements application using RAP-CDS-Modeling.
    • ​Travel ZRK_SDE_I_TRAVEL and Booking zrk_sde_i_booking entities have been generated and ​defined its Behavior definition  ZRK_SDE_I_TRAVEL .
    • As the focus of the blog post is not about data model and to keep the blog post simple, Source code is published in git repository.
  2. Define the required determinations and actions on the specified entities.
    1. ​Determination Calculate_Total_price in Travel entity.

       determination Calculate_Total_price on modify { field BookingFee; }
    2. ​Determination Calculate_Total_price in Booking entity.

      determination calculate_Total_Price on modify { create;  field flightprice; }
    3. Internal action ReCalcTotalPrice​ in Travel entity which is in turn executed in above 2 steps so that business logic is implemented once and consistent. ​

      internal action ReCalcTotalPrice;
    4. Custom action Apply_Discount​ in Booking entity​

       action Apply_Discount parameter zrk_sde_a_apply_disc result [1] $self;
  3. Implement the business logic in ​respective Behavior Pool classes.
    *************** calculate_Total_Price at Travel Entity 
      METHOD Calculate_Total_price.
        "update involved instances
        MODIFY ENTITIES OF zrk_sde_i_travel IN LOCAL MODE
          ENTITY Travel
            EXECUTE recalctotalprice
            FROM CORRESPONDING #( keys ).
      ENDMETHOD.
    
    *************** calculate_Total_Price at Booking Entity 
     METHOD calculate_Total_Price.
        READ ENTITIES OF zrk_sde_i_travel IN LOCAL MODE
            ENTITY Booking
            BY \_Travel
            FIELDS ( TravelUUID )
             WITH CORRESPONDING #( keys )
             RESULT DATA(lt_travels).
    
        "update involved instances
        MODIFY ENTITIES OF zrk_sde_i_travel IN LOCAL MODE
          ENTITY Travel
            EXECUTE recalctotalprice
            FROM VALUE #( FOR <fs_key> IN lt_travels ( %tky = <fs_key>-%tky ) ).
      ENDMETHOD.
    
    
    *************** Internal action - Implementation
      METHOD ReCalcTotalPrice.
    
        READ ENTITIES OF zrk_sde_i_travel IN LOCAL MODE
          ENTITY Travel
            FIELDS ( BookingFee )
               WITH CORRESPONDING #( keys )
             RESULT DATA(lt_travels).
    
        LOOP AT lt_travels ASSIGNING FIELD-SYMBOL(<Fs_travel>).
          <Fs_travel>-TotalPrice = <Fs_travel>-BookingFee.
    
          READ ENTITIES OF zrk_sde_i_travel IN LOCAL MODE
              ENTITY Travel
              BY \_Booking
              FIELDS ( FlightPrice )
               WITH VALUE #( ( %tky = <fs_travel>-%tky ) )
               RESULT DATA(lt_bookings).
    
          LOOP AT lt_bookings ASSIGNING FIELD-SYMBOL(<fs_booking>).
            <Fs_travel>-TotalPrice = <Fs_travel>-TotalPrice + <fs_booking>-FlightPrice.
          ENDLOOP.
    
        ENDLOOP.
    
        "update involved instances
        MODIFY ENTITIES OF zrk_sde_i_travel IN LOCAL MODE
          ENTITY Travel
            UPDATE FIELDS ( TotalPrice )
            WITH VALUE #( FOR travel IN lt_travels  (
                               %tky      = travel-%tky
                               TotalPrice  = travel-TotalPrice ) ).
    
      ENDMETHOD.
      METHOD Apply_Discount.
    
        LOOP AT keys ASSIGNING FIELD-SYMBOL(<fs_key>).
          DATA(lv_disc_percent) = <fs_key>-%param-Discount_percent.
        ENDLOOP.
    
        READ ENTITIES OF zrk_sde_i_travel IN LOCAL MODE
            ENTITY Booking
            FIELDS ( FlightPrice )
             WITH CORRESPONDING #( keys )
             RESULT DATA(lt_bookings).
    
        LOOP AT lt_bookings ASSIGNING FIELD-SYMBOL(<fs_booking>).
          <fs_booking>-FlightPrice = <fs_booking>-FlightPrice * ( 100 - lv_disc_percent ) / 100.
        ENDLOOP.
    
        "update involved instances
        MODIFY ENTITIES OF zrk_sde_i_travel IN LOCAL MODE
          ENTITY Booking
            UPDATE FIELDS ( FlightPrice )
            WITH VALUE #( FOR <fs_book> IN lt_bookings  (
                               %tky      = <fs_book>-%tky
                               FlightPrice  = <fs_book>-FlightPrice  ) ).
    
        READ ENTITIES OF zrk_sde_i_travel IN LOCAL MODE
            ENTITY Booking
            FIELDS ( FlightPrice )
             WITH CORRESPONDING #( keys )
             RESULT DATA(lt_bookings_upd).
    
        RESUlT = VALUE #( FOR <fs_res> IN lt_bookings_upd ( %tky = <fs_res>-%tky %param = <fs_res> ) ) .
    
      ENDMETHOD.
  4. Identify the source properties and target properties/entities for side effects​.
    1. ​​​Determination Calculate_Total_price in Travel entity.
      ​Source : Field – Booking fee ,
      Target : Field – Total price​
    2. ​​​Determination Calculate_Total_price in Booking entity.
      ​Source : Field – Flight price ,
      Target : Field – Total price​ from Travel entity
    3. ​Custom action.
      Source : Action – Apply_Discount
      Target : Field – Total price​ from Travel entity
  5. Define the side effects in Behavior definition ( note: Only once side effects can be defined in a behavior definition )
    define behavior for ZRK_SDE_I_TRAVEL alias Travel
    ...
      side effects
      {
        field BookingFee affects field TotalPrice;
      }​
    define behavior for zrk_sde_i_booking alias Booking
    ...
      side effects
      {
        field FlightPrice affects field _Travel.TotalPrice;
        action Apply_Discount affects field _Travel.TotalPrice ;
      }
  6. ​Expose the side​ effects in Projection level behavior definition so that they are available UI consumption.

    projection;
    strict ( 2 );
    use draft;
    
    use side effects; <<<<<<======= 
    
    define behavior for ZRK_SDE_C_TRAVEL alias Travel
    use etag
    
    {
    
    }
  7. ​Observe the activities ​done by the framework.
    1. ​Metadata definition​:
      As we can see here, all the 3 side effects are converted by the framework in Odata-v4 annotations .

      <Annotations Target="SAP__self.TravelType">
      	<Annotation Term="SAP__common.Label" String="Projection View for ZRK_SDE_I_TRAVEL"/>
      	<Annotation Term="SAP__common.SideEffects" Qualifier="SAP__Field_BookingFee">
      		<Record Type="SAP__common.SideEffectsType">
      			<PropertyValue Property="SourceProperties">
      				<Collection>
      					<PropertyPath>BookingFee</PropertyPath>
      				</Collection>
      			</PropertyValue>
      			<PropertyValue Property="TargetProperties">
      				<Collection>
      					<String>TotalPrice</String>
      				</Collection>
      			</PropertyValue>
      		</Record>
      	</Annotation>
      </Annotations>
      
      
      
      <Annotations Target="SAP__self.BookingsType">
      	<Annotation Term="SAP__common.Label" String="ZRK_SDE_C_BOOKING"/>
      	<Annotation Term="SAP__common.SideEffects" Qualifier="SAP__Field_FlightPrice">
      		<Record Type="SAP__common.SideEffectsType">
      			<PropertyValue Property="SourceProperties">
      				<Collection>
      					<PropertyPath>FlightPrice</PropertyPath>
      				</Collection>
      			</PropertyValue>
      			<PropertyValue Property="TargetProperties">
      				<Collection>
      					<String>_Travel/TotalPrice</String>
      				</Collection>
      			</PropertyValue>
      		</Record>
      	</Annotation>
      </Annotations>
      
      
      
      <Annotations Target="SAP__self.Apply_Discount(SAP__self.BookingsType)">
      	<Annotation Term="SAP__core.OperationAvailable" Path="_it/__OperationControl/Apply_Discount"/>
      	<Annotation Term="SAP__common.SideEffects" Qualifier="SAP__Action_Apply_Discount">
      		<Record Type="SAP__common.SideEffectsType">
      			<PropertyValue Property="TargetProperties">
      				<Collection>
      					<String>_it/_Travel/TotalPrice</String>
      				</Collection>
      			</PropertyValue>
      		</Record>
      	</Annotation>
      </Annotations>
    2. Network calls: ​
      ​As we can see network calls, Read calls for the target properties/entries are automatically fired when the source properties are changed /actions are triggered.



​Conclusion:​

Now we understand what side effects are and how to define/use them and how they work. ​
Please go through documentation from SAP for more information.

Assigned Tags

      12 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Sandra Rossi
      Sandra Rossi

      Thanks. Documentation: Side Effects | SAP Help Portal and Developing Side Effects | SAP Help Portal.

      Author's profile photo Paul Hardy
      Paul Hardy

      This could be described as "ON-CHAIN-INPUT / ON-CHAIN-REQEUST" - the next generation.

      All jokes aside the difference is that in DYNPRO world the business logic was tightly coupled to the UI technolgy, but now the there is a clear seperation.

      The idea is that the "view" is "dumb" and has no business logic. It just does what it is told by the controller.

      This way when a new UI technology comes along to supercede UI5 (and this is just a question of WHEN not IF) there is no need to change the backend (model). In fact in theory now that the RAP is available in the on-premise version of S/4HANA you could have the same back-end logic and present the data in UI5 or (in increasing order of obsolescence) ALV or DYNPRO or WRITE statements or WEB DYNPRO....

      The B side of all this is the blurring of the separation of concerns between the business logic layer and the database layer. With code pushdown this was somewhat inevitable, and happily a whole raft of automated unit testing frameworks are available.

      Cheersy Cheers

      Paul

      Author's profile photo Pavan Kumar Jagadeesh
      Pavan Kumar Jagadeesh

      Hi Ramjee,

      Thanks for the wonderful blog.

      There is a small typo in the blogpost under point 4. I think it should be Travel entity instead of booking.

       

      Thanks,

      Pavan

      Author's profile photo Ramjee Korada
      Ramjee Korada
      Blog Post Author

      Hi Pavan,

      thanks for noticing typo. It is corrected now.

      Best wishes,

      Ramjee Korada

      Author's profile photo Jagdish Patil
      Jagdish Patil

      Hi Ramjee Rana

      Thank you for the post. This is helpful. I have a question.

      The code does not seem to be working in delete scenario for me. When we delete a booking, the below code is triggered but the first READ statement returns empty table.

      *************** calculate_Total_Price at Booking Entity 
       METHOD calculate_Total_Price.
          READ ENTITIES OF zrk_sde_i_travel IN LOCAL MODE
              ENTITY Booking
              BY \_Travel
              FIELDS ( TravelUUID )
               WITH CORRESPONDING #( keys )
               RESULT DATA(lt_travels).  "--> Results in no data in delete scenario
      
          "update involved instances
          MODIFY ENTITIES OF zrk_sde_i_travel IN LOCAL MODE
            ENTITY Travel
              EXECUTE recalctotalprice
              FROM VALUE #( FOR <fs_key> IN lt_travels ( %tky = <fs_key>-%tky ) ).
        ENDMETHOD.
      Author's profile photo Ramjee Korada
      Ramjee Korada
      Blog Post Author

      Hi Jagdish,

      There seems to be general issue with Determination on Delete currently. I will check further and raise a question.

      Best wishes,

      Ramjee Korada.

      Author's profile photo Andre Fischer
      Andre Fischer

      Nice post. 👍

      You can find another simple example in my following blog post How to use side effects in RAP | SAP Blogs and the source code on GitHub abap-platform-code-samples-cloud/README.md at main · SAP-samples/abap-platform-code-samples-cloud (github.com).

      Author's profile photo Ramjee Korada
      Ramjee Korada
      Blog Post Author

      Hi Andre,

      Thank you for the feedback. I have already gone through your blog.

      As this topic is really interesting, I wanted to try with custom action .

      Best wishes ,

      Ramjee Korada.

      Author's profile photo DurgaPrasanth vemula
      DurgaPrasanth vemula

      Hi Ramjee,

       

      As you had mentioned that Source code is published in git repository.Could you please provide me the Github link of this Program.

       

      Thanks

      Prasanth

      Author's profile photo Ramjee Korada
      Ramjee Korada
      Blog Post Author

      Hi Prasanth,

      thanks - updated the blog.

      https://github.com/koradaramjee789/ZRK_SIDE_EFFECTS_RAP.git

       

      Best wishes,

      Ramjee Korada

      Author's profile photo Mario Lenz
      Mario Lenz

      Hi Ramjee,

      thank you so much for your explanation. Do you have any information on when this will be available for on-premise customers? I'd love to use it.

       

      Kind regards

      Mario

      Author's profile photo Ramjee Korada
      Ramjee Korada
      Blog Post Author

      Hi Mario,

      Thank you for the feedback .

      It is planned to be delivered this year release. Please stay tuned on roadmap .

      https://help.sap.com/docs/abap-cross-product/roadmap-info/ui-services?locale=en-US

      Best wishes,

      Ramjee Korada