Association vs Composition, Virtual Elements, Unmanaged and Additional Save in SAP Restful Application Programming

Association vs Composition, Virtual Elements, Unmanaged and Additional Save in SAP Restful Application Programming



Association v/s Composition


In SAP Restful application programming, both association and composition are important concepts related to handling relationships between entities in the context of OData services. Let's delve into each concept:


Association:

  • Definition: An association represents a relationship between two entities where one entity refers to the other. It's a way to define a connection between two entity types without implying ownership or lifecycle dependency.
  • Usage: Associations are used when two entities have a relationship but are independent in terms of lifecycle. For example, a customer and an order are often associated, but an order can exist without a customer (like in an e-commerce system where guest orders are allowed).


Composition:

  • Definition: Composition represents a stronger relationship where one entity "owns" the other and is responsible for its lifecycle. When the owning entity is deleted, the dependent entity is usually deleted as well (although this behavior can be controlled).
  • Usage: Compositions are used when two entities are closely related and one entity cannot exist without the other or has a lifecycle dependency. For instance, in an HR system, an employee might have a composition relationship with their dependents, meaning if the employee record is deleted, the dependent records should also be deleted.



In SAP Restful application programming, we'll often encounter scenarios where we need to decide between association and composition based on the nature of the relationship between entities.



Associations are more loosely coupled and suitable when entities have independent lifecycles, while compositions imply a stronger relationship and lifecycle dependency between entities.


The choice between these two depends on specific business logic and data model requirements.



We can consider Sales Order example to create composite based RAP application.


Here we will create 3 table (Header , Item and Billing table ) to demonstrate the functionality. Where item and billing details are tightly linked/dependent on header information.


Header Table

@EndUserText.label : 'header details'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zheader {

  key client         : abap.clnt not null;
  key hdrkey         : sysuuid_x16 not null;
  inv_re_no          : abap.char(10) not null;
  ship_loc           : abap.char(25);
  sales_area         : abap.char(25);
  part_no            : abap.char(10);
  ship_status        : abap.char(2);
  uom                : meins;
  @Semantics.quantity.unitOfMeasure : 'zheader.uom'
  ship_quan          : abap.quan(10,0);
  @Semantics.quantity.unitOfMeasure : 'zheader.uom'
  reciev_quan        : abap.quan(10,0);
  upd_by             : abap.char(10);
  upd_at             : timestampl;
  locallastchangedat : timestampl;

}        



Item Table


@EndUserText.label : 'Item table for CAP BTP'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zitem {

  key client   : abap.clnt not null;
  @AbapCatalog.foreignKey.screenCheck : false
  key hdrkey   : sysuuid_x16 not null
    with foreign key zheader
      where client = zitem.client
        and hdrkey = zitem.hdrkey;
  key itmkey   : sysuuid_x16 not null;
  inv_re_no    : abap.char(10) not null;
  item_no      : abap.numc(3);
  itm_status   : abap.char(10);
  sales_office : abap.char(10);
  uom          : meins;
  @Semantics.quantity.unitOfMeasure : 'zheader.uom'
  delv_qty     : abap.quan(10,0);
  @Semantics.quantity.unitOfMeasure : 'zheader.uom'
  apr_qty      : abap.quan(10,0);

}        

Billing Information : This table would be storing final amount after discount .


@EndUserText.label : 'billing table'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zbilling {

  key client : abap.clnt not null;
  @AbapCatalog.foreignKey.screenCheck : false
  key hdrkey : sysuuid_x16 not null
    with foreign key zheader
      where client = zbilling.client
        and hdrkey = zbilling.hdrkey;
  key itmkey : sysuuid_x16 not null;
  inv_re_no  : abap.char(10) not null;
  item_no    : abap.numc(3);
  discount   : abap.numc(2);

}        

Now comes the most important part of designing the Business Object( BO) .


A business object is common term to refer real world artifact in enterprise application development such as product , travel or sales order.


In general, a business object contains several nodes such as Items and Schedule Lines and common transactional operations such as for creating, updating and deleting business data.


Lets start designing the Nodes . We will create 3 different CDS view (each of tables).



While designing CDS view we need to mention parent and child relationship using composition.



Header Interface Root View


@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'header info'
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.usageType:{
    serviceQuality: #X,
    sizeCategory: #S,
    dataClass: #MIXED
}
define root view entity zi_header_info as select from  zheader composition[0..*] of zi_item_info as _Item
 composition[0..*] of zi_billing_info as _billing

{
    key hdrkey as Hdrkey,
    inv_re_no as InvReNo,
    ship_loc as ShipLoc,
    sales_area as SalesArea,
    part_no as PartNo,
    ship_status as ShipStatus,
    uom as Uom,
//  @Semantics.quantity.unitOfMeasure : 'zheader.uom'
//    ship_quan as ShipQuan,
  
//    reciev_quan as RecievQuan,
    upd_by as UpdBy,
   @Semantics.systemDateTime.lastChangedAt: true
    upd_at as upd_at,
    @Semantics.systemDateTime.localInstanceLastChangedAt:true 
     locallastchangedat as locallastchangedat ,
       
   
    _Item,
    _billing
}
        


Item CDS View

@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'item info'
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.usageType:{
    serviceQuality: #X,
    sizeCategory: #S,
    dataClass: #MIXED
}
define view entity zi_item_info as select from  zitem association to parent  ZI_Header_info as _Header on $projection.Hdrkey = _Header.Hdrkey
{
    
    key hdrkey as Hdrkey,
    key itmkey as Itmkey,
    inv_re_no as InvReNo,
    item_no as ItemNo,
    itm_status as ItmStatus,
    sales_office as SalesOffice,
    uom as Uom,
    @Semantics.quantity.unitOfMeasure : 'UOM'
    delv_qty as DelvQty,
    @Semantics.quantity.unitOfMeasure : 'UOM'
    apr_qty as AprQty,
    _Header
    
}

        

Billing CDS View


@AbapCatalog.viewEnhancementCategory: [#NONE]
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Billing details'
@Metadata.ignorePropagatedAnnotations: true
@ObjectModel.usageType:{
    serviceQuality: #X,
    sizeCategory: #S,
    dataClass: #MIXED
}
define  view entity zi_billing_info as select from zbilling association to parent  zi_header_info as _Header on $projection.Hdrkey = _Header.Hdrkey
{
key zbilling.hdrkey as Hdrkey,
key zbilling.itmkey as Itmkey,
zbilling.inv_re_no as InvReNo,
zbilling.item_no as ItemNo,
zbilling.discount as Discount,
_Header

    
}

        


Now Our base model is ready . We will follow RAP practice to create projection view and here we need to define Parent and child relationship explicitly in PROJECTION CDS.

 

WE DEFINE PARENT CHILD relationship in PROJECTION CDS.


Projection of Header Root View



@EndUserText.label: 'Projection of Header Entity'
@AccessControl.authorizationCheck: #NOT_REQUIRED
@Metadata.allowExtensions: true
define root view entity zc_header_info as projection on zi_header_info
{

  
  key Hdrkey,
  InvReNo,
  ShipLoc,
  SalesArea,
  PartNo,
  ShipStatus,
  Uom,
  UpdBy,
  upd_at,
  locallastchangedat as locallastchangedat ,
  @ObjectModel.virtualElementCalculatedBy: 'ABAP:ZCL_VIRTUALFL'
                  @UI: {
          lineItem:       [ { position: 50, importance: #HIGH } ],
          identification: [ { position: 50, label: 'Amount' } ] }
      @Search.defaultSearchElement: true
        
  virtual Amount : abap.int4,
  /* Associations */
  _Item : redirected to composition child zc_item_info  ,
  _billing : redirected to composition child zc_billing_info  
}

        


Note : We will talk about Virtual Element implementation in details in later part of article.


Projection of Item CDS View


@EndUserText.label: 'Projection of Item Entity'
@AccessControl.authorizationCheck: #NOT_REQUIRED
@Metadata.allowExtensions: true
define view entity zc_item_info as projection on zi_item_info
{
    key Hdrkey,
    key Itmkey,
    InvReNo,
    ItemNo,
    ItmStatus,
    SalesOffice,
    Uom,
    DelvQty,
    AprQty,
    /* Associations */
    _Header: redirected to parent zc_header_info
}

        


Projection of Billing CDS view

@EndUserText.label: 'billing info'
@AccessControl.authorizationCheck: #NOT_REQUIRED
define  view entity zc_billing_info as projection on zi_billing_info
{
    key Hdrkey,
    key Itmkey, 
    @UI.facet: [ { id:              'Invreno',
                     purpose:         #STANDARD,
                     type:            #IDENTIFICATION_REFERENCE,
                     label:           'Invreno',
                     position:        10 }        
                         
         
              ]
//     @UI: {
//          lineItem:       [ { position: 10, importance: #HIGH } ],
//          identification: [ { position: 10, label: 'InvReNo' } ] }
//     
    @UI: {
          lineItem:       [ { position: 10, importance: #HIGH } ],
          identification: [ { position: 10, label: 'InvReNo' } ] }        
    InvReNo,
        @UI: {
          lineItem:       [ { position: 20, importance: #HIGH } ],
          identification: [ { position: 20, label: 'ItemNo' } ] }
    ItemNo,
     @UI: {
          lineItem:       [ { position: 30, importance: #HIGH } ],
          identification: [ { position: 30, label: 'Discount' } ] }
    Discount,
    /* Associations */
    _Header :  redirected to parent zc_header_info
   
}

        




NOW our Business Object is ready. We need to create Behavior definition on top of Interface view and Projection view(ROOT VIEW).

managed implementation in class zbp_i_header_info unique;
strict(2) ;
with draft;

define behavior for zi_header_info //alias <alias_name>
persistent table zheader
lock master total etag upd_at
authorization master ( instance )
etag master locallastchangedat

{
  create;
  update;
  delete;

  association _Item { create;  }
  association _billing { create;  }
}


define behavior for zi_item_info //alias <alias_name>
persistent table zitem
lock dependent by _Header
authorization dependent by _Header
{
  update;
  delete;
  association _Header;
}
define behavior for zi_billing_info //alias <alias_name>
persistent table zbilling
lock dependent by _Header
authorization dependent by _Header
{

  update;
  delete;
  association _Header;
  
}        

 

If We notice on Behavior definition ,Header entity is allowed for CREATE,UPADTE,DELETE and framework as auto added entry for ITEM and BILLING create on the basis of HEADER data through below code.


association _Item { create;  }
  association _billing { create;  }        


Above association is mandatory for Item and billing data creation on the basis of header.

Likewise below association defined in ITEM and Billing behavior definition .


 association _Header;        


 NOTE : When we have right click on interface CDS of Header (that marked as root) , framework has auto generated below code for behavior with header ,item and billing information with association defined.

BUT WHY ?? Because it has composition relationship .

 

NOTE : HEADER is ROOT entity only .(Behavior definition can only be created on ROOT entity).



Now we will create behavior definition on Projection CDS of Header entity.


projection;
strict ( 2 );
use draft;

define behavior for zc_header_info //alias <alias_name>
{
 use create;
  use update;
  use delete;
  
  use association _Item { create; }
  use association _billing { create; }
}

define behavior for zc_item_info //alias <alias_name>
{
  use update;
  use delete;

  use association _Header;
}
define behavior for zc_billing_info //alias <alias_name>
{
  use update;
  use delete;

  use association _Header;
}        


Note : Metadata annotations plays important role while designing application. I am providing metadata extension as well of CDS entities for reference.


Facet is most important annotation here that design the object page and with the help of parent-child relationship defined on behavior definition we will be able to see CREATE ,UPDATE,DELETE buttons on object page for ITEM data.


Header Metadata Ext

@Metadata.layer: #CORE
annotate view zc_header_info
    with 
{
    @UI.facet: [ { id:              'Invreno',
                     purpose:         #STANDARD,
                     type:            #IDENTIFICATION_REFERENCE,
                     label:           'Invreno',
                     position:        10 
                     }  ,      
                     
              {
              type: #LINEITEM_REFERENCE,
              position: 20,
              label: 'Items',
              targetElement: '_Item'
              },
                            {
              type: #LINEITEM_REFERENCE,
              position: 30,
              label: 'Billing',
              targetElement: '_billing'
              }
                         
              ]
    Hdrkey ;

    @UI: {
          lineItem:       [ { position: 10, importance: #HIGH } ],
          identification: [ { position: 10, label: 'Inv. Receipt No' } ] }
      @Search.defaultSearchElement: true
      
      
        InvReNo;
        
    @UI: {
          lineItem:       [ { position: 20, importance: #HIGH } ],
          identification: [ { position: 20, label: 'Ship Loc' } ],
          selectionField: [{ position: 10 }] }
      @Search.defaultSearchElement: true
        ShipLoc;
        
        @UI: {
          lineItem:       [ { position: 30, importance: #HIGH } ],
          identification: [ { position: 30, label: ' Sales Area' } ] }
      @Search.defaultSearchElement: true
        SalesArea;
        
        @UI: {
          lineItem:       [ { position: 40, importance: #HIGH } ],
          identification: [ { position: 40, label: 'Ship Status' } ] }
      @Search.defaultSearchElement: true
        ShipStatus;



}        


Item Metadata Ext

@Metadata.layer: #CUSTOMER
annotate view zc_item_info
    with 
{
 @UI.facet: [ { id:              'Invreno',
                     purpose:         #STANDARD,
                     type:            #IDENTIFICATION_REFERENCE,
                     label:           'Invreno',
                     position:        10 }        
                         
         
              ]
              
        @UI: {
          lineItem:       [ { position: 10, importance: #HIGH } ],
          identification: [ { position: 10, label: 'ITem No' } ] }
   
 
    ItemNo;
       @UI: {
          lineItem:       [ { position: 30, importance: #HIGH } ],
          identification: [ { position: 30, label: 'Status' } ] }
    ItmStatus;
       @UI: {
          lineItem:       [ { position: 40, importance: #HIGH } ],
          identification: [ { position: 40, label: 'Salesoffice' } ] }
    SalesOffice;
       @UI: {
          lineItem:       [ { position: 50, importance: #HIGH } ],
          identification: [ { position: 50, label: 'Uom' } ] }
    Uom;
       @UI: {
          lineItem:       [ { position: 60, importance: #HIGH } ],
          identification: [ { position: 60, label: 'Deliver Quantity' } ] }
       
    DelvQty;
       @UI: {
          lineItem:       [ { position: 70, importance: #HIGH } ],
          identification: [ { position: 70, label: 'Approved Quantity' } ] }
        
    AprQty;
    
    
}        


Note: We have not created separate metadata ext for billing , annotations is written in billing CDS view.



Now we will create service definition and expose projection views of Header , item and Billing.

@EndUserText.label: 'Service binding on projection entity'
define service Zsd_sales_order {
  expose zc_header_info;
  expose zc_item_info;
  expose zc_billing_info;
}        


Create Service binding and preview the application.


Select one record and check object page.

We can Create, Update and Delete records . RAP framework would be taking care of operations based on composition relation mentioned in behavior definition and on BO.



Virtual Element


A "virtual element" could refer to an element that is not directly stored in the database but is dynamically generated or calculated based on other data elements.


These virtual elements can be exposed through the service to provide additional functionality or information to consumers without the need for explicit storage.


To demonstrate virtual element , we have added virtual element in projection root view (can only be added in projection).


Header Projection View


Below annotation is mandatory to define virtual element.

@ObjectModel.virtualElementCalculatedBy: 'ABAP:ZCL_VIRTUALFL'        

Class ZCL_VIRTUALFL would be used to implement business logic of virtual element which will have below interface.


INTERFACES if_sadl_exit_calc_element_read.        

Interface will have below two methods.

GET_CALCULATION_INFO - used to collect data before sending to CALCULATE method for actual business logic implementation. 

CALCULATE - Actual business Logic        


We have created ZCL_VIRTUALFL and wrote sample code to populate value into virtual element.


Calculate method implementation

Activate class and preview the application.


Virtual Element 'Amount' auto Populated


That's how we can make use of virtual element.


SAVE OPTIONS


In managed scenarios, there are three options for setting up the save phase.

we can use the built-in save sequence of the managed scenario, which is the default for any managed RAP BO.


Based on the default save sequence, we can add additional implementations with the additional save.


As an alternative to the save method of the managed save sequence runtime, we can implement our own save method as an unmanaged save.


Managed SAVE

Unmanaged SAVE

Additional SAVE


Unmanaged Save


In SAP RAP "unmanaged save" refers to a concept related to handling data persistence and transactions in a more manual or explicit manner compared to the default managed save operations provided by RAP framework.

Here are the key points to understand about unmanaged save in SAP RAP:


Managed vs. Unmanaged Save


  • Managed Save: In managed save operations, the RAP framework automatically manages the lifecycle of database transactions during CRUD (Create, Read, Update, Delete) operations. It handles transaction boundaries, error handling, and data consistency implicitly.
  • Unmanaged Save: On the other hand, unmanaged save gives developers more control over transaction management. It means developers are responsible for explicitly defining and managing transaction boundaries, committing or rolling back transactions, and handling errors manually


Use Case


  • Managed Save: Typically used in standard scenarios where the RAP framework handles transaction management transparently, making development easier and less error-prone.


  • Unmanaged Save: Useful in specific cases where developers need fine-grained control over transaction behavior, such as when dealing with complex transactional logic, batch processing, or integrating with external systems with specific transactional requirements.



We can make use of unmanaged save to make calculation before saving data to DB.


We will be updating discount field of Billing table on the basis of incoming data on Header and Item table with the help of unmanaged save.


We need to make below changes in behavior definition .

1.Remove persistent table

2. mark unmanaged save


Behavior Definition

managed implementation in class zbp_i_header_info unique;
strict(2) ;
with draft;

define behavior for zi_header_info //alias <alias_name>
//persistent table zheader
with unmanaged save
draft table ztdr_header
lock master total etag upd_at
authorization master ( instance )
etag master locallastchangedat

{
  create;
  update;
  delete;
   field ( numbering : managed , readonly ) Hdrkey ;

draft action Edit;
draft action Activate;
draft action Discard;
draft action Resume;
draft determine action prepare;

  mapping for zheader { Hdrkey = hdrkey;
                        InvReNo = inv_re_no;
                        PartNo = part_no;
                        SalesArea = sales_area;
                        ShipLoc = ship_loc;
                        ShipStatus = ship_status;
                        upd_at = upd_at;
                        locallastchangedat = locallastchangedat ;

                        }
  association _Item { create; with draft; }
  association _billing { create;  }
}


define behavior for zi_item_info //alias <alias_name>
//persistent table zitem
draft table ztdr_item
with unmanaged save
lock dependent by _Header
authorization dependent by _Header
{
  update;
  delete;
//  field ( numbering : managed , readonly )  Itmkey;
  field ( readonly) hdrkey;
  association _Header;
  mapping for zitem { Hdrkey = hdrkey;
                      InvReNo = inv_re_no;
                      ItemNo = item_no;
                      ItmStatus =  itm_status;
                      SalesOffice = sales_office;
                      Uom = uom;
                      AprQty = apr_qty;
                      DelvQty = delv_qty;

                        }

}
define behavior for zi_billing_info //alias <alias_name>
//persistent table zbilling
draft table ztdr_billing
with unmanaged save
lock dependent by _Header
authorization dependent by _Header
{

  update;
  delete;
//  field ( numbering : managed , readonly )  Itmkey;
  field ( readonly) hdrkey;
  association _Header;
  mapping for zbilling{

    Hdrkey = hdrkey;
  Itmkey = itmkey;
 InvReNo = inv_re_no;
  ItemNo = item_no ;
  Discount = discount;
  }

}        


Now we need to create new class extending class cl_abap_behavior_saver (Add in Behavior Imp class).


Method SAVE_MODIFIED would be use to write business logic to commit /rollback changes to DB.


cl_abap_behavior_saver



Below are the Parameter of Method SAVE_MODIFIED.


CREATE,UPDATE,DELETE- WILL hold values in case of respective operations


For demonstrate purpose , we have hardcoded 99 as discount value . We can write actual business logic and modify DB tables.


CLASS lhc_zi_header_info DEFINITION INHERITING FROM cl_abap_behavior_handler.
  PRIVATE SECTION.

    METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION
      IMPORTING keys REQUEST requested_authorizations FOR zi_header_info RESULT result.



ENDCLASS.

CLASS lhc_zi_header_info IMPLEMENTATION.

  METHOD get_instance_authorizations.
  ENDMETHOD.

ENDCLASS.

CLASS lsc_zi_header_info DEFINITION INHERITING FROM cl_abap_behavior_saver.

  PROTECTED SECTION.
*
    METHODS save_modified REDEFINITION.

ENDCLASS.

CLASS lsc_zi_header_info IMPLEMENTATION.

  METHOD save_modified.

  data: lit_header type table of zheader,
        lit_item   type table of zitem,
        lit_billing type table of zbilling,
        wa_billing type zbilling.

  IF create IS NOT INITIAL.

      lit_header = CORRESPONDING #( create-zi_header_info MAPPING FROM ENTITY ).
      modify zheader FROM TABLE @lit_header.

      lit_item = CORRESPONDING #( create-zi_item_info MAPPING FROM ENTITY ).
      modify zitem FROM TABLE @lit_item .
*
      lit_billing = CORRESPONDING #( create-zi_billing_info MAPPING FROM ENTITY ).
        lit_billing[ 1 ]-discount = 99.
      MODIFY zbilling FROM TABLE @lit_billing .

    ENDIF.

  if update is not INITIAL.

  ENDIF.
    ...
  ENDMETHOD.

ENDCLASS.        

We can put breakpoint and debug in case of issue.



Additional Save


Additional save refers to implementing custom logic or enhancements that occur in addition to the standard save operations provided by SAP RAP.


In certain situations, an application may need to call an external function during the process of saving data. This should happen after the system has collected the updated information for business objects but before it completes the final save operation.


Additional Save - Triggers after standard save performed by framework

Unmanaged Save - There is no standard save, whole control is on developer hand.



SAVE Sequence

In order to integrate the additional save into the save sequence as a part of the managed runtime, we must first add the corresponding syntax to the behavior definition and then implement the saver handler method as a part of the behavior pool.


Both save options( additional and unmanaged save ) make use of class cl_abap_behavior_saver.


Code implementation of additional save is exactly same as we did to handle unmanaged save.



Sample code of inheriting CL_ABAP_BEHAVIOR_SAVER .

CLASS lcl_saver DEFINITION INHERITING FROM cl_abap_behavior_saver.

  PROTECTED SECTION.
    METHODS save_modified REDEFINITION.

ENDCLASS.


CLASS lcl_saver IMPLEMENTATION.

  METHOD save_modified.

    IF CREATE-EntityName IS NOT INITIAL.

      " Provide table of instance data of all instances that have been created during current transaction

      " Use %CONTROL to get information on what entity fields have been set when creating the instance 

    ENDIF.

    IF UPDATE-EntityName IS NOT INITIAL.

      " Provide table of instance data of all instances that have been updated during current transaction

      " Use %CONTROL to get information on what entity fields have been updated  
    ENDIF.

    IF DELETE-EntityName IS NOT INITIAL.

      " Provide table with keys of all instances that have been deleted during current transaction

      " NOTE: There is no information on fields when deleting instances 

    ENDIF.

  ENDMETHOD.

  ...

ENDCLASS.

        


Thanks for Reading!



Reference




VINAY KUMAR .P

Abap on Hana|| RAP || SAP Certified Associate - back-end developer - ABAP Cloud

7mo

Very helpful 🙌🏼🙌🏼🙌🏼.but I need full application code for that example.

Like
Reply
George Drakos

SAP Technical Consultant | S/4 HANA and SAP UI5/Fiori | On Premise and Cloud | SAP Certified Development Specialist | MBA

7mo

Great article. Many thanks for your effort 👍

Sadullah TANRIKULU

ABAP || Javascript || Life Coach

8mo

With a quick look, I got this : Association is between same level entities and Composition is that one entity owns other. Especially in Composition concept e.g. a personal record deleted rest of its dependents should be deleted. Great blog, thanks for the contribution to the community. 🤙

Like
Reply
Bandaru madhuri

SAP ABAP|RAP|Workflow consultant

8mo

Very helpful!

Like
Reply

To view or add a comment, sign in

More articles by Satya Prakash Tiwari

Insights from the community

Others also viewed

Explore topics