Technology Blogs by SAP
Learn how to extend and personalize SAP applications. Follow the SAP technology blog for insights into SAP BTP, ABAP, SAP Analytics Cloud, SAP HANA, and more.
cancel
Showing results for 
Search instead for 
Did you mean: 
Andre_Fischer
Product and Topic Expert
Product and Topic Expert
There have been several questions in the community how unmanaged scenarios with draft are handled in the ABAP RESTful Application Programming Model (RAP).

An important fact that is not well known is, that the draft that is added to an unmanaged scenario itself is managed.

Therefore I was able to reuse the implementation of the managed Flight sample /DMO/I_Travel_M that also uses semantic keys and early numbering.

I plan to publish several examples based on the on well known on premise Enterprise Procurement Data Model that comes with Products, Business Partners, Sales Orders and Sales Order Items where I would like to address the special requirements when you have to handle BAPI calls in on premise systems.

However to answer the most pressing question that was how semantic key fields are populated in a draft enabled scenario I started to implement a first small sample based on the travel sample.

1. Handling of semantic key fields


The problem with semantic key fields in draft scenarios is that when creating several draft entities they all will be created with an empty key. Already when trying to create a second item a short dump will be raised which indicates that it was tried to insert an entry into the draft table with a duplicated key.
A duplicate primary key '00000000' was detected when inserting data into persistence 'ZTRAVELSEM00D_01'.

Solution : Early Numbering


The documentation about early numbering can be found here:

Internal Early Numbering - SAP Help Portal

To demonstrate the use of internal early numbering in an unmanaged scenario I have created the following Z-table based on the flight reference scenario:
@EndUserText.label : 'Flight Reference Scenario: Managing Travels'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table ztravel_sem_01 {
key client : abap.clnt not null;
key travel_id : /dmo/travel_id not null;
description_2 : abap.char(50);
gr_data : include /dmo/travel_data;
gr_admin : include /dmo/travel_admin;

}

 

In the behavior definition (BDEF) we have to specify that early numbering is used.

 
unmanaged;
with draft;

define behavior for ZI_TRAVELSEMANTIC_01 alias TravelSemantic
implementation in class ZBP_I_TRAVELSEMANTIC_01 unique
draft table ztravelsem00d_01
etag master Lastchangedat
lock master total etag Lastchangedat
early numbering
authorization master ( global )

{
field ( readonly )
TravelID;


create;
update;
delete;

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

mapping for ZTRAVEL_SEM_01 control ZSTravelSemantic_X_01
{
TravelID = TRAVEL_ID;
Description2 = DESCRIPTION_2;
AgencyID = AGENCY_ID;
CustomerID = CUSTOMER_ID;
BeginDate = BEGIN_DATE;
EndDate = END_DATE;
BookingFee = BOOKING_FEE;
TotalPrice = TOTAL_PRICE;
CurrencyCode = CURRENCY_CODE;
Description = DESCRIPTION;
Status = STATUS;
Createdby = CREATEDBY;
Createdat = CREATEDAT;
Lastchangedby = LASTCHANGEDBY;
Lastchangedat = LASTCHANGEDAT;
}
}

 

In the behavior implementation class we have to add a method of type FOR NUMBERING.
METHODS earlyNumbering_Create FOR NUMBERING
IMPORTING entities FOR CREATE TravelSemantic.

In the implementation of this method (code see below) we have first to check for which entities which have been handed over to us the key field is not yet set.

Then we calculate the travelid that should be used. Here we use a poor mans approach by simply selecting the highest value for a travelid from the normal as well as from the draft table.

Since we are in the create phase the %tky is not yet filled. So we have to populate the mapped return table with values for %cid, %key and %is_draft that were handed over to us by the RAP framework.

Usually you will use a number range here or if the semantic key values are provided by the BAPI you would use those.

Result


After having added the early numbering statement in the BDEF and after having implemented the method earlyNumbering_Create the app works correctly and provides TravelID's for each newly created draft elements.


 

Pitfalls


When you simply start with entering the method for early numbering in your behavior implementation class you get the error message
The operation 'CREATE' is not activated for entity "ZI_TRAVELSEMANTIC_01".

though the create method is part of the behavior definition. What was actually missing in the BDEF was the early numbering statement .



Code


CLASS lhc_travelsemantic DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS:
get_global_authorizations FOR GLOBAL AUTHORIZATION
IMPORTING
REQUEST requested_authorizations FOR TravelSemantic
RESULT result,
create FOR MODIFY
IMPORTING
entities FOR CREATE TravelSemantic,
update FOR MODIFY
IMPORTING
entities FOR UPDATE TravelSemantic,
delete FOR MODIFY
IMPORTING
keys FOR DELETE TravelSemantic,
lock FOR LOCK
IMPORTING
keys FOR LOCK TravelSemantic,
read FOR READ
IMPORTING
keys FOR READ TravelSemantic
RESULT result.

METHODS earlyNumbering_Create FOR NUMBERING
IMPORTING entities FOR CREATE TravelSemantic.

ENDCLASS.

CLASS lhc_travelsemantic IMPLEMENTATION.
METHOD get_global_authorizations.
ENDMETHOD.
METHOD create.
ENDMETHOD.
METHOD update.
ENDMETHOD.
METHOD delete.
ENDMETHOD.
METHOD lock.
ENDMETHOD.
METHOD read.
ENDMETHOD.


METHOD earlynumbering_create.

DATA:
* entity TYPE STRUCTURE FOR CREATE /DMO/I_Travel_M,
travel_id_max TYPE /dmo/travel_id.

" Ensure Travel ID is not set yet (idempotent)- must be checked when BO is draft-enabled
LOOP AT entities INTO DATA(entity) WHERE travelid IS NOT INITIAL.
APPEND CORRESPONDING #( entity ) TO mapped-travelsemantic.
ENDLOOP.

DATA(entities_wo_travelid) = entities.
DELETE entities_wo_travelid WHERE travelid IS NOT INITIAL.

"Get max travelID
SELECT SINGLE FROM ztravel_sem_01 FIELDS MAX( travel_id ) INTO @DATA(max_travelid).

" select from draft table
SELECT SINGLE FROM ztravelsem00d_01 FIELDS MAX( travelid ) INTO @DATA(max_travelid_draft).

IF max_travelid < max_travelid_draft.
max_travelid = max_travelid_draft.
ELSEIF max_travelid = 0.
max_travelid += 1.
ENDIF.


" Set Travel ID
LOOP AT entities_wo_travelid INTO entity.
max_travelid += 1.
entity-travelid = max_travelid .

APPEND VALUE #( %cid = entity-%cid
"%tky is not available since we are in create
%key = entity-%key
"needed because we are using draft
%is_draft = entity-%is_draft
) TO mapped-travelsemantic.
ENDLOOP.

ENDMETHOD.

ENDCLASS.
CLASS lcl_zi_travelsemantic_01 DEFINITION INHERITING FROM cl_abap_behavior_saver.
PROTECTED SECTION.
METHODS:
finalize REDEFINITION,
check_before_save REDEFINITION,
save REDEFINITION,
cleanup REDEFINITION,
cleanup_finalize REDEFINITION.
ENDCLASS.

CLASS lcl_zi_travelsemantic_01 IMPLEMENTATION.
METHOD finalize.
ENDMETHOD.
METHOD check_before_save.
ENDMETHOD.
METHOD save.
ENDMETHOD.
METHOD cleanup.
ENDMETHOD.
METHOD cleanup_finalize.
ENDMETHOD.
ENDCLASS.

 

 

 
8 Comments
Pavan_Golesar
Active Participant
0 Kudos
Thanks Andre, Will give this a try soon.

Warm Regards,

Pavan Golesar
wagenbma
Explorer
0 Kudos
Hi Andre,

Thanks for your blog. Can you please explain how to use early numberig to realize the requirement that the key values are not determined by the application but entered manually by the user in the UI?

I am searching already a long time for a solution, but do not find one.

 

Kind regards,
Matthias
Andre_Fischer
Product and Topic Expert
Product and Topic Expert
0 Kudos
If you follow this exercise the application that is initially generated will behave such that you can enter any key value for travel data.

Only later in Exercise number 2 internal numbering is implemented.

abap-platform-rap-workshops/rap1xx/rap100 at main · SAP-samples/abap-platform-rap-workshops (github....

 

Kind regards,

Andre
hegde_dhananjay
Explorer
Hello Andre

 

Thank you for the post. Very interesting.

I tried Unmanaged Draft with Semantic Keys scenario with Late Numbering.  This works as well.  Tried this in BTP Trial today.  More details here in this comment on another post on this topic.

Late Numbering might be particularly useful when numbers are drawn from number range.

But, I noticed, in BTP Trial, EDIT does not work as of now.  POST request to call EDIT action fails. It fails to generate a draft.

With ODATA V2, I get an error "No Data Found".

With ODATA V4, I get an error "Unspecified provider error occurred. See Error Context and Call Stack".

As far as I know, "EDIT" action for Unmanaged with Draft should work without needing any "additional implementation".

Is this not fully supported yet on BTP Trial?

 

Thank you,

Dhananjay
Kishore
Participant
0 Kudos

Hello Andre

I have a requirement where I need to pull the data from different standard tables. On these records I should provide an option to update few fields. On saving this, we need to make a standard FM/BAPI call to update these values.

This case doesn't have any base table so I cannot have have a field to mention for "total etag". What should be the recommended approach for draft handling in this case or is it possible to have a draft scenario here?

My requirement is only to update. I don't need create and delete options.

Thanks,

Kishore.

 

sandeeps026
Explorer
0 Kudos
Hello Dhananjay,

you have to give implementation for read method to solve that 'No Data Found' error.


Regards,

Sandeep.

shavneet1
Participant
0 Kudos
Hello Sandeep / andre.fischer .

I am also Stuck in this 'No data found error' when clicking on Edit button. My requirement is , Actual data is already coming from legacy system. there is no create or delete.

Just few actions and Update of data , on Edit and Save.

sandeeps026 : can you please give more details.

 

Regards ,

Shavneet
matiasmiano1982
Explorer
0 Kudos
Hi Kishore,

 

Did you solve that requirement? I've a similar one and I do not know how to continue.

 

Regards

Matias