You have created a RAP BO based on one or more customizing tables by using the BC Maintenance Object ADT Wizard as described in this tutorial.
You want to extend the RAP BO by adding an additional customizing table to the data model.
The business configuration maintenance object supports RAP BO whose height of the composition tree is less than or equal to 2. For example, root entity A has two child entities B and C. Entity C has a child entity D. D cannot have any further child entities.
Depending on the back-end version, while the ADT wizard can handle multiple tables at the same time, the most complex supported scenarios require a manual enhancement after generation.
This blog is relevant for:
Further reading:
You have used the following table ZCB_HEAD with the ADT wizard to generate a maintenance object:
@EndUserText.label : 'Header'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #C
@AbapCatalog.dataMaintenance : #ALLOWED
define table zcb_head {
key client : abap.clnt not null;
key head_key : zcb_id not null;
head_content : abap.char(30);
last_changed_at : abp_lastchange_tstmpl;
local_last_changed_at : abp_locinst_lastchange_tstmpl;
}
The table ZCB_ITEM that you want to add has the following structure and is a child entity of table ZCB_HEAD:
@EndUserText.label : 'Item'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #C
@AbapCatalog.dataMaintenance : #ALLOWED
define table zcb_item {
key client : abap.clnt not null;
@AbapCatalog.foreignKey.keyType : #KEY
@AbapCatalog.foreignKey.screenCheck : false
key head_key : zcb_id not null
with foreign key zcb_head
where client = zcb_item.client
and head_key = zcb_item.head_key;
key item_key : abap.numc(3) not null;
item_content : abap.char(30);
local_last_changed_at : abp_locinst_lastchange_tstmpl;
}
Create a CDS view for table ZCB_ITEM with
@EndUserText.label: 'Header'
@AccessControl.authorizationCheck: #CHECK
@Metadata.allowExtensions: true
define view entity ZI_Item
as select from zcb_item
association to parent ZI_Header as _Header on $projection.HeadKey = _Header.HeadKey
association [1..1] to ZI_Header_S as _HeaderAll on $projection.SingletonID = _HeaderAll.SingletonID
{
key head_key as HeadKey,
key item_key as ItemKey,
item_content as ItemContent,
@Semantics.systemDateTime.localInstanceLastChangedAt: true
@Consumption.hidden: true
local_last_changed_at as LocalLastChangedAt,
@Consumption.hidden: true
1 as SingletonID,
_Header,
_HeaderAll
}
Add a composition to ZI_Item in the CDS View of table ZCB_HEAD:
@EndUserText.label: 'Header'
@AccessControl.authorizationCheck: #CHECK
define view entity ZI_Header
as select from zcb_head
association to parent ZI_Header_S as _HeaderAll on $projection.SingletonID = _HeaderAll.SingletonID
composition [0..*] of ZI_Item as _Item
{
key head_key as HeadKey,
head_content as HeadContent,
@Semantics.systemDateTime.lastChangedAt: true
last_changed_at as LastChangedAt,
@Semantics.systemDateTime.localInstanceLastChangedAt: true
@Consumption.hidden: true
local_last_changed_at as LocalLastChangedAt,
@Consumption.hidden: true
1 as SingletonID,
_HeaderAll,
_Item
}
If you have a projection layer, create a projection CDS view for ZI_Item with redirection to entity ZC_Header and the singleton entity. Save and activate.
@AccessControl.authorizationCheck: #CHECK
@Metadata.allowExtensions: true
@EndUserText.label: 'Maintain Item'
define view entity ZC_Item as projection on ZI_Item
{
key HeadKey,
key ItemKey,
ItemContent,
@Consumption.hidden: true
LocalLastChangedAt,
@Consumption.hidden: true
SingletonID,
_Header : redirected to parent ZC_Header,
_HeaderAll : redirected to ZC_Header_S
}
If you have a projection layer, add a redirection to composition child ZI_Item in the projection CDS view of ZI_Header:
@EndUserText.label: 'Maintain Header'
@AccessControl.authorizationCheck: #CHECK
@Metadata.allowExtensions: true
define view entity ZC_Header
as projection on ZI_Header
{
key HeadKey,
HeadContent,
LastChangedAt,
@Consumption.hidden: true
LocalLastChangedAt,
@Consumption.hidden: true
SingletonID,
_HeaderAll : redirected to parent ZC_Header_S,
_Item : redirected to composition child ZC_Item
}
In the behavior definition ZI_HEADER_S, add the following definition for entity ZI_Item:
define behavior for ZI_Item alias Item
persistent table ZCB_ITEM
draft table ZCB_ITEM_D
etag master LocalLastChangedAt
lock dependent by _HeaderAll
authorization dependent by _HeaderAll
{
field ( mandatory : create )
ItemKey;
field ( readonly )
SingletonID,
HeadKey,
LocalLastChangedAt;
field ( readonly : update )
ItemKey;
field ( notrigger )
SingletonID,
LocalLastChangedAt;
update( features : global );
delete( features : global );
mapping for ZCB_ITEM
{
HeadKey = HEAD_KEY;
ItemKey = ITEM_KEY;
ItemContent = ITEM_CONTENT;
LocalLastChangedAt = LOCAL_LAST_CHANGED_AT;
}
association _HeaderAll { with draft; }
association _Header { with draft; }
validation ValidateTransportRequest on save ##NOT_ASSIGNED_TO_DETACT { create; update; delete; }
}
In the entity definition of ZI_Header, add an association to ZI_Item:
association _Item { create ( features : global ); with draft; }
Save the behavior definition. Place the cursor on the draft table ZCB_ITEM_D and use the quick assist (Ctrl+1) to generate the draft table. After activating the draft table, activate the behavior definition.
Place the cursor on ZI_Item underlined by a warning message and use the quick assist to generate the missing method implementations.
If you have a projection layer, adjust the behavior projection:
projection;
strict;
use draft;
define behavior for ZC_Header_S alias HeaderAll
{
use action Edit;
use action Activate;
use action Discard;
use action Resume;
use action Prepare;
use action SelectCustomizingTransptReq;
use association _Header { create; with draft; }
}
define behavior for ZC_Header alias Header
{
use update;
use delete;
use association _HeaderAll { with draft; }
use association _Item { create; with draft; }
}
define behavior for ZC_Item alias Item
{
use update;
use delete;
use association _HeaderAll { with draft; }
use association _Header { with draft; }
}
Edit the behavior implementation class.
Add the table entity relation for ZCB_ITEM:
CLASS LHC_RAP_TDAT_CTS IMPLEMENTATION.
METHOD GET.
result = mbc_cp_api=>rap_tdat_cts( tdat_name = 'ZHEADER'
table_entity_relations = VALUE #(
( entity = 'Header' table = 'ZCB_HEAD' )
( entity = 'Item' table = 'ZCB_ITEM' )
) ) ##NO_TEXT.
ENDMETHOD.
ENDCLASS.
Implement the methods of LHC_ZI_ITEM and move the class definition LHC_RAP_TDAT_CTS up:
CLASS lhc_rap_tdat_cts DEFINITION FINAL.
PUBLIC SECTION.
CLASS-METHODS:
get
RETURNING
VALUE(result) TYPE REF TO if_mbc_cp_rap_tdat_cts.
ENDCLASS.
CLASS lhc_item DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS get_global_features FOR GLOBAL FEATURES
IMPORTING REQUEST requested_features FOR Item RESULT result.
METHODS ValidateTransportRequest FOR VALIDATE ON SAVE
IMPORTING keys FOR Item~ValidateTransportRequest.
ENDCLASS.
CLASS lhc_item IMPLEMENTATION.
METHOD get_global_features.
DATA edit_flag TYPE abp_behv_flag VALUE if_abap_behv=>fc-o-enabled.
IF lhc_rap_tdat_cts=>get( )->is_editable( ) = abap_false.
edit_flag = if_abap_behv=>fc-o-disabled.
ENDIF.
result-%update = edit_flag.
result-%delete = edit_flag.
ENDMETHOD.
METHOD ValidateTransportRequest.
DATA change TYPE REQUEST FOR CHANGE ZI_Header_S.
SELECT SINGLE TransportRequestID
FROM zcb_head_d_s
WHERE SingletonID = 1
INTO (TransportRequestID).
lhc_rap_tdat_cts=>get( )->validate_changes(
transport_request = TransportRequestID
table = 'ZCB_ITEM'
keys = REF #( keys )
reported = REF #( reported )
failed = REF #( failed )
change = REF #( change-item ) ).
ENDMETHOD.
ENDCLASS.
If you are using the VALIDATE_ALL_CHANGES method, delete the ValidateTransportRequest method from the LHC_ITEM class and adjust the ValidateTransportRequest method of the LHC_ZI_HEADER class:
VALIDATETRANSPORTREQUEST FOR VALIDATE ON SAVE
IMPORTING
KEYS_HEADER FOR Header~ValidateTransportRequest
KEYS_ITEM FOR Item~ValidateTransportRequest.
[...]
METHOD VALIDATETRANSPORTREQUEST.
DATA change TYPE REQUEST FOR CHANGE ZI_Header_S.
IF keys_Header IS NOT INITIAL.
DATA(is_draft) = keys_Header[ 1 ]-%IS_DRAFT.
ELSEIF keys_Item IS NOT INITIAL.
is_draft = keys_Item[ 1 ]-%IS_DRAFT.
ELSE.
RETURN.
ENDIF.
READ ENTITY IN LOCAL MODE ZI_Header_S
FROM VALUE #( ( %IS_DRAFT = is_draft
SingletonID = 1
%CONTROL-TransportRequestID = if_abap_behv=>mk-on ) )
RESULT FINAL(transport_from_singleton).
IF lines( transport_from_singleton ) = 1.
DATA(transport_request) = transport_from_singleton[ 1 ]-TransportRequestID.
ENDIF.
lhc_rap_tdat_cts=>get( )->validate_all_changes(
transport_request = transport_request
table_validation_keys = VALUE #(
( table = 'ZCB_HEAD' keys = REF #( keys_Header ) )
( table = 'ZCB_ITEM' keys = REF #( keys_Item ) )
)
reported = REF #( reported )
failed = REF #( failed )
change = REF #( change ) ).
ENDMETHOD.
Add the %ASSOC-_Item statement to the GET_GLOBAL_FEATURES method of LHC_ZI_HEADER:
METHOD get_global_features.
DATA edit_flag TYPE abp_behv_flag VALUE if_abap_behv=>fc-o-enabled.
IF lhc_rap_tdat_cts=>get( )->is_editable( ) = abap_false.
edit_flag = if_abap_behv=>fc-o-disabled.
ENDIF.
result-%update = edit_flag.
result-%delete = edit_flag.
result-%ASSOC-_Item = edit_flag.
ENDMETHOD.
Create a metadata extension for ZI_Item or ZC_Item when using a projection layer:
@Metadata.layer: #CUSTOMER
@UI: {
headerInfo: {
typeName: 'Item',
typeNamePlural: 'Items',
title: {
type: #STANDARD,
label: 'Item',
value: 'ItemKey'
}
}
}
annotate entity ZC_Item with
{
@UI.identification: [ {
position: 1 ,
label: 'ItemKey'
} ]
@UI.lineItem: [ {
position: 1 ,
label: 'ItemKey'
} ]
@UI.facet: [ {
id: 'ZI_Item',
purpose: #STANDARD,
type: #IDENTIFICATION_REFERENCE,
label: 'Item',
position: 1
} ]
ItemKey;
@UI.identification: [ {
position: 2 ,
label: 'ItemContent'
} ]
@UI.lineItem: [ {
position: 2 ,
label: 'ItemContent'
} ]
ItemContent;
}
Add a facet to _Item in the metadata extension of ZI_Header or ZC_Header when using a projection layer:
[...]
annotate entity ZC_Header with
{
@UI.identification: [ {
position: 1
} ]
@UI.lineItem: [ {
position: 1
} ]
@UI.facet: [ {
id: 'ZI_Header',
purpose: #STANDARD,
type: #IDENTIFICATION_REFERENCE,
label: 'Header',
position: 1
},
{
id: 'ZI_Item',
type: #LINEITEM_REFERENCE,
label: 'Item',
position: 2 ,
targetElement: '_Item'
} ]
HeadKey;
[...]
Create an access control object for ZI_Item:
@MappingRole: true
define role ZI_Item {
grant select on ZI_Item
where INHERITING CONDITIONS FROM ENTITY ZI_Header;
}
If you are using a projection layer, create an access control object for ZC_Item:
@MappingRole: true
define role ZC_Item {
grant select on ZC_Item
where INHERITING CONDITIONS FROM ENTITY ZI_Item;
}
Add table ZCB_ITEM to the transport object definition ZHEADER:
"tableItems": [
{
"tableName": "ZCB_HEAD",
"isPrimaryTable": true
},
{
"tableName": "ZCB_ITEM"
}
]
If you are using SAP S/4HANA On Premises 2023, use transaction SOBJ instead of ADT to adjust the transport object definition.
Add entity ZC_Item to the service definition:
define service ZUI_HEADER {
expose ZC_Header_S as HeaderAll;
expose ZC_Header as Header;
expose ZC_Item as Item;
}
No adjustments are necessary. You have the option to define specific table settings for the new entity, for example, to change the table creation mode.
You can now restart the Custom Business Configurations app to review the changes.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
User | Count |
---|---|
27 | |
25 | |
19 | |
13 | |
13 | |
11 | |
10 | |
8 | |
7 | |
6 |