
CDS - Writable View Entity
Can you perform an update to a Core Data Service in ABAP? Let's look at the new CDS view entities.
Table of contents
What about updating data in database tables? Is there a CDS alternative if the table entity is not yet fully available? In this article, we'll look at a current solution.
Introduction
With Release 2502, a new entity was introduced in the ABAP Environment in the Core Data Services area: the "Writable View Entity". Unfortunately, we can't find any information in the current news about ABAP Release 9.14. While searching for more in-depth information, we only came across a few links and would therefore like to try out for ourselves what we can currently do with the new entities.
Preparation
Let's start by creating some objects that we need for the test. To do this, we first create a DDIC table in the system, which we need for writing. The table is intended to represent a company; the key is a UUID, along with the name and description, as well as a classification of the company.
@EndUserText.label : 'Writable Table'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zbs_dmo_write {
key client : abap.clnt not null;
key company_uuid : sysuuid_x16 not null;
name : abap.char(60);
description : abap.sstring(1333);
classification : abap.char(1);
}
To have some data in the table, we create an executable class. There, we fill an internal table with data, delete the old data, and insert the new data.
CLASS zcl_bs_demo_writable DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PRIVATE SECTION.
METHODS initialize_database
IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.
ENDCLASS.
CLASS zcl_bs_demo_writable IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
initialize_database( out ).
ENDMETHOD.
METHOD initialize_database.
DATA write_database TYPE STANDARD TABLE OF zbs_dmo_write WITH EMPTY KEY.
write_database = VALUE #( ( company_uuid = xco_cp=>uuid( )->value name = 'SAP' classification = 'S' )
( company_uuid = xco_cp=>uuid( )->value name = 'Accenture' classification = 'C' )
( company_uuid = xco_cp=>uuid( )->value name = 'Microsoft' classification = 'S' )
( company_uuid = xco_cp=>uuid( )->value name = 'McKinsey' classification = 'C' )
( company_uuid = xco_cp=>uuid( )->value name = 'Deloitte' classification = 'C' ) ).
DELETE FROM zbs_dmo_write.
INSERT zbs_dmo_write FROM TABLE @write_database.
COMMIT WORK.
out->write( `Data created on database:` ).
out->write( write_database ).
ENDMETHOD.
ENDCLASS.
In the next step, we create the writable entity. You can use the template for the VIEW ENTITY for the attachment to do this. After generation, we normalize the database fields for the Core Data Service and insert the WRITABLE keyword between DEFINE and VIEW.
@AccessControl.authorizationCheck: #CHECK
@EndUserText.label: 'Writable Entity'
define writable view entity ZBS_B_DMOWritable
as select from zbs_dmo_write
{
key company_uuid as CompanyUUID,
name as Name,
description as Description,
classification as Classification
}
The entity is now fully defined. In the next step, we define an access control for the test on the Core Data Service and restrict access to the classification "C" (Consultant).
@EndUserText.label: 'Access Control'
@MappingRole: true
define role ZBS_B_DMOWRITABLE {
grant
select
on
ZBS_B_DMOWRITABLE
where
Classification = 'C';
}
This creates our test artifacts, and we can begin testing in the next step.
Update
In this chapter, we'll look at changes to the database. To do this, we'll update the company descriptions in various scenarios. We'll use a helper method, SELECT_COMPANY_BY_NAME, to read the company record from the table, not the Core Data Service. When reading, the access control would take effect and not return all the data.
Database
So we first read the record and then update the description to send the new data to the database via an UPDATE.
DATA(accenture) = select_company_by_name( 'Accenture' ).
accenture-description = `Accenture plc is a global multinational professional services company`.
UPDATE zbs_dmo_write FROM @accenture.
Writeable Entity (Allowed)
In the second example, we use our new entity for writing, reading a record for which we would also be authorized. In the next step, we need to map the data, as we receive it from the database with the different names. In the case of a Core Data Service, this step would no longer be necessary. We would perform the UPDATE exactly as we did with the database.
DATA(deloitte) = select_company_by_name( 'Deloitte' ).
DATA(deloitte_update) = VALUE ZBS_B_DMOWritable(
CompanyUUID = deloitte-company_uuid
Name = deloitte-name
Description = `Deloitte is a multinational professional services network based in London`
Classification = deloitte-classification ).
UPDATE ZBS_B_DMOWritable FROM @deloitte_update.
Writeable Entity (Not Allowed)
In the last example, we would read a record for which we don't have permissions. However, to prepare the data for the update, we read it from the table. Then the data is updated.
DATA(sap) = select_company_by_name( 'SAP' ).
DATA(sap_update) = VALUE ZBS_B_DMOWritable(
CompanyUUID = sap-company_uuid
Name = sap-name
Description = `SAP SE is a European multinational software company based in Walldorf`
Classification = sap-classification ).
UPDATE ZBS_B_DMOWritable FROM @sap_update.
Result
So what does the result of the action look like? If we execute the class, we get the following output in the ABAP console. All updates appear to have worked.
If we then check the contents of the table, we also see that all companies have received a description.
Summary
This means that two facts are certain so far:
- We can forward changes to the underlying database via the Writable View Entity.
- The defined access control limits the display and reading of data, but not currently the writing.
The Writable View Entity can use the current model with Core Data Services complement this, as it eliminates the need to map data from the Core Data Service to the table, especially if no suitable RAP object is available. Write access restrictions are not currently delivered with the entity, so an authorization check should be performed beforehand to determine whether the user has the necessary permissions. Therefore, you shouldn't rely on the developer only being able to see half of the data.
If you were thinking of trying to model across multiple data sources, perhaps to update a data model via a view, this doesn't currently work.
Complete Example
You can find the various artifacts in the various chapters and sections above. For the sake of completeness, here is the class we use for execution.
CLASS zcl_bs_demo_writable DEFINITION
PUBLIC FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PRIVATE SECTION.
METHODS initialize_database
IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.
METHODS update_database
IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.
METHODS update_writable_allowed
IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.
METHODS select_company_by_name
IMPORTING !name TYPE zbs_dmo_write-name
RETURNING VALUE(result) TYPE zbs_dmo_write.
METHODS handle_update_result
IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.
METHODS update_writable_not_allowed
IMPORTING !out TYPE REF TO if_oo_adt_classrun_out.
ENDCLASS.
CLASS zcl_bs_demo_writable IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
initialize_database( out ).
update_database( out ).
update_writable_allowed( out ).
update_writable_not_allowed( out ).
ENDMETHOD.
METHOD initialize_database.
DATA write_database TYPE STANDARD TABLE OF zbs_dmo_write WITH EMPTY KEY.
write_database = VALUE #( ( company_uuid = xco_cp=>uuid( )->value name = 'SAP' classification = 'S' )
( company_uuid = xco_cp=>uuid( )->value name = 'Accenture' classification = 'C' )
( company_uuid = xco_cp=>uuid( )->value name = 'Microsoft' classification = 'S' )
( company_uuid = xco_cp=>uuid( )->value name = 'McKinsey' classification = 'C' )
( company_uuid = xco_cp=>uuid( )->value name = 'Deloitte' classification = 'C' ) ).
DELETE FROM zbs_dmo_write.
INSERT zbs_dmo_write FROM TABLE @write_database.
COMMIT WORK.
out->write( `Data created on database:` ).
out->write( write_database ).
ENDMETHOD.
METHOD select_company_by_name.
SELECT SINGLE FROM zbs_dmo_write
FIELDS *
WHERE name = @name
INTO @result.
ENDMETHOD.
METHOD update_database.
DATA(accenture) = select_company_by_name( 'Accenture' ).
accenture-description = `Accenture plc is a global multinational professional services company`.
out->write( 'Table ZBS_DEMO_WRITE' ).
UPDATE zbs_dmo_write FROM @accenture.
handle_update_result( out ).
ENDMETHOD.
METHOD update_writable_allowed.
DATA(deloitte) = select_company_by_name( 'Deloitte' ).
DATA(deloitte_update) = VALUE ZBS_B_DMOWritable(
CompanyUUID = deloitte-company_uuid
Name = deloitte-name
Description = `Deloitte is a multinational professional services network based in London`
Classification = deloitte-classification ).
out->write( 'CDS ZBS_B_DMOWritable (Allowed)' ).
UPDATE ZBS_B_DMOWritable FROM @deloitte_update.
handle_update_result( out ).
ENDMETHOD.
METHOD update_writable_not_allowed.
DATA(sap) = select_company_by_name( 'SAP' ).
DATA(sap_update) = VALUE ZBS_B_DMOWritable(
CompanyUUID = sap-company_uuid
Name = sap-name
Description = `SAP SE is a European multinational software company based in Walldorf`
Classification = sap-classification ).
out->write( 'CDS ZBS_B_DMOWritable (Not allowed)' ).
UPDATE ZBS_B_DMOWritable FROM @sap_update.
handle_update_result( out ).
ENDMETHOD.
METHOD handle_update_result.
IF sy-subrc = 0.
out->write( |Update was successful: { sy-subrc }| ).
COMMIT WORK.
ELSE.
out->write( |Update was not successful: { sy-subrc }| ).
ROLLBACK WORK.
ENDIF.
ENDMETHOD.
ENDCLASS.
Conclusion
Writing the data in the Core Data Service format? This is now possible with the Writable View Entity, which could complement the Table Entity as a supplement to the classic tables without triggering a large migration wave.
Further information:
SAP Community - ABAP News for SAP BTP ABAP Environment 2502
SAP Help - Writable View Entities