Validations in BOPF and Consistency Validation in BOPF

Estimated read time 14 min read

Hello Everyone,

In this blog we will be going to learn about the Validations in BOPF.

What is Validation in BOPF? 

In BOPF, a validation is a consistency check defined on a node of the business object that ensures the data fulfills specific business rules before it is saved or processed. 

In BOPF, keeping the data clean and consistent is very important. Validations help achieve this by checking the data against specific rules. Just like determinations, validations are created on the node of the data model where they are needed. Today, we’ll walk you through how to create a validation and write the logic for it in the implementation class. 

Procedure  

Here we are defining a custom Travel table (zkk_dt_travel). 

@EndUserText.label : ‘Data base table for Travel Details’
@AbapCatalog.enhancement.category : #EXTENSIBLE_ANY
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #ALLOWED
define table zkk_dt_travel {

key client : abap.clnt not null;
key travel_id : zkk_de_travel_id not null;
key user_email : zkk_de_email not null;
start_date : dats;
destination : zkk_de_destination;
status : zkk_de_status;
expense_type : zkk_de_item_type;
@Semantics.amount.currencyCode : ‘zkk_travel_hdr.curr_key’
total_cost : zkk_de_cost;
curr_key : zkk_de_cost_key;
remarks : zkk_de_remarks;
created_by : zkk_de_createdby;
created_on : datum;

}

The above table has the below shown data.

For the Database table we are defining the Basic view  

@AbapCatalog.sqlViewName: ‘ZKK_DBV_TRAVEL’
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Interface view for Travel details’
@Metadata.ignorePropagatedAnnotations: true
@Metadata.allowExtensions: true

@ObjectModel:{
modelCategory: #BUSINESS_OBJECT,
compositionRoot: true,
transactionalProcessingEnabled: true,
writeActivePersistence: ‘ZKK_dt_travel’,

createEnabled: true,
updateEnabled: true,
deleteEnabled: true
}

@OData.publish: true
define view zi_kk_travel
as select from zkk_dt_travel
{
key travel_id,
@ObjectModel.mandatory: true
key user_email,
start_date,
destination,
status,
@ObjectModel.mandatory: true
expense_type,
@ObjectModel.mandatory: true
total_cost,
curr_key,
remarks,
created_by,
created_on
}

For creating the Business object directly from the Eclipse editor, we have to make use of annotations which I have given with their functionality 

Here’s the explanation of each annotation in your snippet: 

@ObjectModel: { 
 modelCategory: #BUSINESS_OBJECT, 
 compositionRoot: true, 
 transactionalProcessingEnabled: true, 
 writeActivePersistence: ‘ZKK_dt_travel’, 
 
 createEnabled: true, 
 updateEnabled: true, 
 deleteEnabled: true 
} 
 Explanation 

modelCategory: #BUSINESS_OBJECT 

Declares that the CDS view represents a Business Object (BO). This means it can be used in BOPF to handle business logic and transactional operations. 

compositionRoot: true 

Defines this entity as the root node of the Business Object. Other nodes (child entities) can be linked to it via composition relationships. 

transactionalProcessingEnabled: true 

Enables transactional behavior (create, update, delete, save, rollback) for the entity, making it suitable for business object processing. 

writeActivePersistence: ‘ZKK_dt_travel’ 

Specifies the database table (ZKK_DT_TRAVEL) where the active (persisted) data of this entity is stored. 

createEnabled: true 

Allows the creation of new records in the entity. 

updateEnabled: true 

Allows modification of existing records. 

deleteEnabled: true 

Allows deletion of records. 

@odata.publish: true    turns your CDS view into an OData service provider, making its data available for consumption via OData protocols. 

In short: 

This annotation block is used to define a CDS entity as a Business Object root node with full CRUD (Create, Read, Update, Delete) support and persistence in the custom table ZKK_DT_TRAVEL. 

Here I am creating the Metadata extension for the Basic view (ZI_KK_TRAVEL) for consuming it in the front end. 

@Metadata.layer: #CORE
@UI.headerInfo: {
typeName: ‘Travel’,
typeNamePlural: ‘Travel Details’
}
annotate entity zi_kk_travel
with
{
@UI.facet: [{
id: ‘Travel’,
purpose: #STANDARD,
position: 10,
label: ‘Travel Details ‘,
type: #IDENTIFICATION_REFERENCE
} ]
@UI.lineItem: [{ position: 10, label: ‘Travel Id’ }]
@UI.identification: [{ position: 10 }]
travel_id;
@UI.lineItem: [{ position: 20, label: ‘Email’ }]
@UI.identification: [{ position: 20 }]
user_email;
@UI.lineItem: [{ position: 30, label: ‘Travel Date’ }]
@UI.identification: [{ position: 30 }]
start_date;
@UI.lineItem: [{ position: 40, label: ‘Destination’ }]
@UI.identification: [{ position: 40 }]
destination;
@UI.lineItem: [{ position: 50, label: ‘Status’ }]
@UI.identification: [{ position: 50 }]
status;
@UI.lineItem: [{ position: 60, label: ‘Expense Type’ }]
@UI.identification: [{ position: 60 }]
expense_type;
@UI.lineItem: [{ position: 65, label: ‘Amount’ }]
@UI.identification: [{ position: 65 }]
total_cost;
@UI.lineItem: [{ position: 70, label: ‘Currency’ }]
@UI.identification: [{ position: 70 }]
curr_key;
@UI.lineItem: [{ position: 80, label: ‘Remarks for Expense’ }]
@UI.identification: [{ position: 80 }]
remarks;
@UI.lineItem: [{ position: 85, label: ‘Created By’ }]
@UI.identification: [{ position: 10 }]
created_by;
@UI.lineItem: [{ position: 90, label: ‘Created Date’ }]
@UI.identification: [{ position: 90 }]
created_on;
}

 Now activate the Basic view and the meta data extension, when it gets activated the Business Object get created implicitly. 

Now open the BOBX Transaction. 

We can search the business object in Home business objects or click on the below marked option.

Provide the BO name which is our Basic View name (ZI_KK_TRAVEL) 

Now to Implement the validations expand the Node Elements  

Right Click on Validations will see the option to Create Validations 

Provide the Validation Name and Description and Class for implementing the validation logic. 

Double click on Class Name, and create a class which will be having the super class implicitly 

Now we have to provide Triggering conditions for the validations, so select the Node instance and tick on Create, Update, Delete and Check  

Save it and check and generate it. 

After this we have to go to eclipse and create a service definition on basic view (ZI_KK_TRAVEL) 

Now create a Service binding on top of Service definition and publish it  

When we preview it  

It will be navigated to the frontend while navigating it will ask for your SAP GUI Credentials to login.

Now go to SE91 Transaction and create a message class

Here, I am doing Validation for a Single status field only so i have passed only two messages  

Now I want to provide the Validations for Status field, so go to our class which we have created in Validations 

Implement our Custom login in this method.

METHOD /bobf/if_frw_validation~execute.

CLEAR : et_failed_key, eo_message.
eo_message = /bobf/cl_frw_factory=>get_message( ).
DATA : lt_data TYPE ztikk_travel, ” Table type for header node
ls_msg TYPE symsg.
io_read->retrieve(
EXPORTING
iv_node = is_ctx-node_key
it_key = it_key
iv_fill_data = abap_true
it_requested_attributes = VALUE #(
( zif_i_kk_travel_c=>sc_node_attribute-zi_kk_travel-status )
) )
IMPORTING
et_data = lt_data
).
LOOP AT lt_data REFERENCE INTO DATA(ls_data).
IF ls_data->status IS INITIAL .
ls_msg-msgid = ‘ZKK_MSG_BOPF’.
ls_msg-msgno = ‘000’.
ls_msg-msgty = ‘E’.

eo_message->add_message(
is_msg = ls_msg ” Message that is to be added to the message object
iv_node = is_ctx-node_key ” Node to be used in the origin location
iv_key = ls_data->key ” Instance key to be used in the origin location
iv_attribute = zif_i_kk_travel_c=>sc_node_attribute-zi_kk_travel-status
” Attribute to be used in the origin location
).

INSERT VALUE #( key = ls_data->key ) INTO TABLE et_failed_key.
ENDIF.

DATA(lv_status) = to_upper( condense( ls_data->status ) ).
IF lv_status NA ‘ACCEPT’ OR lv_status NA ‘REJECT’.
ls_msg-msgid = ‘ZKK_MSG_BOPF’.
ls_msg-msgno = ‘001’.
ls_msg-msgty = ‘E’.

eo_message->add_message(
is_msg = ls_msg
iv_node = is_ctx-node_key
iv_key = ls_data->key
iv_attribute = zif_i_kk_travel_c=>sc_node_attribute-zi_kk_travel-status
).

INSERT VALUE #( key = ls_data->key ) INTO TABLE et_failed_key.
ENDIF.
ENDLOOP.
ENDMETHOD.

Now go to service binding and preview it. Try to create a new record. 

Here I am keeping Status field as empty so it will throw error. 

Now Status should accept only ‘ACCEPT’ or ‘REJECT’. If I try to give any other value it will throw error again. 

If you give the correct value ‘Accept’ or ‘Reject’. 

Conclusion

Validations in BOPF play a vital role in safeguarding data quality and enforcing business rules at the framework level. By defining validations directly on the business object nodes, we ensure that only consistent and compliant data enters the system, regardless of whether it originates from an SAP UI, an external interface, or a background process. This not only strengthens the reliability of the application but also reduces the need for redundant checks across different layers. In short, validations serve as a powerful and centralized mechanism to guarantee data integrity within the BOPF model.

 

​ Hello Everyone,In this blog we will be going to learn about the Validations in BOPF.What is Validation in BOPF? In BOPF, a validation is a consistency check defined on a node of the business object that ensures the data fulfills specific business rules before it is saved or processed. In BOPF, keeping the data clean and consistent is very important. Validations help achieve this by checking the data against specific rules. Just like determinations, validations are created on the node of the data model where they are needed. Today, we’ll walk you through how to create a validation and write the logic for it in the implementation class. Procedure  Here we are defining a custom Travel table (zkk_dt_travel). @EndUserText.label : ‘Data base table for Travel Details’
@AbapCatalog.enhancement.category : #EXTENSIBLE_ANY
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #ALLOWED
define table zkk_dt_travel {

key client : abap.clnt not null;
key travel_id : zkk_de_travel_id not null;
key user_email : zkk_de_email not null;
start_date : dats;
destination : zkk_de_destination;
status : zkk_de_status;
expense_type : zkk_de_item_type;
@Semantics.amount.currencyCode : ‘zkk_travel_hdr.curr_key’
total_cost : zkk_de_cost;
curr_key : zkk_de_cost_key;
remarks : zkk_de_remarks;
created_by : zkk_de_createdby;
created_on : datum;

}The above table has the below shown data.For the Database table we are defining the Basic view  @AbapCatalog.sqlViewName: ‘ZKK_DBV_TRAVEL’
@AbapCatalog.compiler.compareFilter: true
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: ‘Interface view for Travel details’
@Metadata.ignorePropagatedAnnotations: true
@Metadata.allowExtensions: true

@ObjectModel:{
modelCategory: #BUSINESS_OBJECT,
compositionRoot: true,
transactionalProcessingEnabled: true,
writeActivePersistence: ‘ZKK_dt_travel’,

createEnabled: true,
updateEnabled: true,
deleteEnabled: true
}

@OData.publish: true
define view zi_kk_travel
as select from zkk_dt_travel
{
key travel_id,
@ObjectModel.mandatory: true
key user_email,
start_date,
destination,
status,
@ObjectModel.mandatory: true
expense_type,
@ObjectModel.mandatory: true
total_cost,
curr_key,
remarks,
created_by,
created_on
}For creating the Business object directly from the Eclipse editor, we have to make use of annotations which I have given with their functionality Here’s the explanation of each annotation in your snippet: @ObjectModel: {  modelCategory: #BUSINESS_OBJECT,  compositionRoot: true,  transactionalProcessingEnabled: true,  writeActivePersistence: ‘ZKK_dt_travel’,   createEnabled: true,  updateEnabled: true,  deleteEnabled: true }  Explanation modelCategory: #BUSINESS_OBJECT Declares that the CDS view represents a Business Object (BO). This means it can be used in BOPF to handle business logic and transactional operations. compositionRoot: true Defines this entity as the root node of the Business Object. Other nodes (child entities) can be linked to it via composition relationships. transactionalProcessingEnabled: true Enables transactional behavior (create, update, delete, save, rollback) for the entity, making it suitable for business object processing. writeActivePersistence: ‘ZKK_dt_travel’ Specifies the database table (ZKK_DT_TRAVEL) where the active (persisted) data of this entity is stored. createEnabled: true Allows the creation of new records in the entity. updateEnabled: true Allows modification of existing records. deleteEnabled: true Allows deletion of records. @odata.publish: true    turns your CDS view into an OData service provider, making its data available for consumption via OData protocols. In short: This annotation block is used to define a CDS entity as a Business Object root node with full CRUD (Create, Read, Update, Delete) support and persistence in the custom table ZKK_DT_TRAVEL. Here I am creating the Metadata extension for the Basic view (ZI_KK_TRAVEL) for consuming it in the front end. @Metadata.layer: #CORE
@UI.headerInfo: {
typeName: ‘Travel’,
typeNamePlural: ‘Travel Details’
}
annotate entity zi_kk_travel
with
{
@UI.facet: [{
id: ‘Travel’,
purpose: #STANDARD,
position: 10,
label: ‘Travel Details ‘,
type: #IDENTIFICATION_REFERENCE
} ]
@UI.lineItem: [{ position: 10, label: ‘Travel Id’ }]
@UI.identification: [{ position: 10 }]
travel_id;
@UI.lineItem: [{ position: 20, label: ‘Email’ }]
@UI.identification: [{ position: 20 }]
user_email;
@UI.lineItem: [{ position: 30, label: ‘Travel Date’ }]
@UI.identification: [{ position: 30 }]
start_date;
@UI.lineItem: [{ position: 40, label: ‘Destination’ }]
@UI.identification: [{ position: 40 }]
destination;
@UI.lineItem: [{ position: 50, label: ‘Status’ }]
@UI.identification: [{ position: 50 }]
status;
@UI.lineItem: [{ position: 60, label: ‘Expense Type’ }]
@UI.identification: [{ position: 60 }]
expense_type;
@UI.lineItem: [{ position: 65, label: ‘Amount’ }]
@UI.identification: [{ position: 65 }]
total_cost;
@UI.lineItem: [{ position: 70, label: ‘Currency’ }]
@UI.identification: [{ position: 70 }]
curr_key;
@UI.lineItem: [{ position: 80, label: ‘Remarks for Expense’ }]
@UI.identification: [{ position: 80 }]
remarks;
@UI.lineItem: [{ position: 85, label: ‘Created By’ }]
@UI.identification: [{ position: 10 }]
created_by;
@UI.lineItem: [{ position: 90, label: ‘Created Date’ }]
@UI.identification: [{ position: 90 }]
created_on;
} Now activate the Basic view and the meta data extension, when it gets activated the Business Object get created implicitly. Now open the BOBX Transaction. We can search the business object in Home business objects or click on the below marked option.Provide the BO name which is our Basic View name (ZI_KK_TRAVEL) Now to Implement the validations expand the Node Elements  Right Click on Validations will see the option to Create Validations Provide the Validation Name and Description and Class for implementing the validation logic. Double click on Class Name, and create a class which will be having the super class implicitly Now we have to provide Triggering conditions for the validations, so select the Node instance and tick on Create, Update, Delete and Check  Save it and check and generate it. After this we have to go to eclipse and create a service definition on basic view (ZI_KK_TRAVEL) Now create a Service binding on top of Service definition and publish it  When we preview it  It will be navigated to the frontend while navigating it will ask for your SAP GUI Credentials to login.Now go to SE91 Transaction and create a message class Here, I am doing Validation for a Single status field only so i have passed only two messages  Now I want to provide the Validations for Status field, so go to our class which we have created in Validations Implement our Custom login in this method. METHOD /bobf/if_frw_validation~execute.

CLEAR : et_failed_key, eo_message.
eo_message = /bobf/cl_frw_factory=>get_message( ).
DATA : lt_data TYPE ztikk_travel, ” Table type for header node
ls_msg TYPE symsg.
io_read->retrieve(
EXPORTING
iv_node = is_ctx-node_key
it_key = it_key
iv_fill_data = abap_true
it_requested_attributes = VALUE #(
( zif_i_kk_travel_c=>sc_node_attribute-zi_kk_travel-status )
) )
IMPORTING
et_data = lt_data
).
LOOP AT lt_data REFERENCE INTO DATA(ls_data).
IF ls_data->status IS INITIAL .
ls_msg-msgid = ‘ZKK_MSG_BOPF’.
ls_msg-msgno = ‘000’.
ls_msg-msgty = ‘E’.

eo_message->add_message(
is_msg = ls_msg ” Message that is to be added to the message object
iv_node = is_ctx-node_key ” Node to be used in the origin location
iv_key = ls_data->key ” Instance key to be used in the origin location
iv_attribute = zif_i_kk_travel_c=>sc_node_attribute-zi_kk_travel-status
” Attribute to be used in the origin location
).

INSERT VALUE #( key = ls_data->key ) INTO TABLE et_failed_key.
ENDIF.

DATA(lv_status) = to_upper( condense( ls_data->status ) ).
IF lv_status NA ‘ACCEPT’ OR lv_status NA ‘REJECT’.
ls_msg-msgid = ‘ZKK_MSG_BOPF’.
ls_msg-msgno = ‘001’.
ls_msg-msgty = ‘E’.

eo_message->add_message(
is_msg = ls_msg
iv_node = is_ctx-node_key
iv_key = ls_data->key
iv_attribute = zif_i_kk_travel_c=>sc_node_attribute-zi_kk_travel-status
).

INSERT VALUE #( key = ls_data->key ) INTO TABLE et_failed_key.
ENDIF.
ENDLOOP.
ENDMETHOD.Now go to service binding and preview it. Try to create a new record. Here I am keeping Status field as empty so it will throw error. Now Status should accept only ‘ACCEPT’ or ‘REJECT’. If I try to give any other value it will throw error again. If you give the correct value ‘Accept’ or ‘Reject’. ConclusionValidations in BOPF play a vital role in safeguarding data quality and enforcing business rules at the framework level. By defining validations directly on the business object nodes, we ensure that only consistent and compliant data enters the system, regardless of whether it originates from an SAP UI, an external interface, or a background process. This not only strengthens the reliability of the application but also reduces the need for redundant checks across different layers. In short, validations serve as a powerful and centralized mechanism to guarantee data integrity within the BOPF model.   Read More Application Development and Automation Blog Posts articles 

#SAP

You May Also Like

More From Author