In this beginner blog post we are going to see how we can use Large Objects (LOBs) in ABAP Restful Application Programming Model.
In this blog post we are going to see how to Upload File in ABAP Restful Application Programming Model.
Annotation used to to work with Large Objects is @Semantics.largeObject
Previous Blog Posts
ABAP RAP – Instance Authorization
ABAP RAP – Global Authorization
ABAP RAP – #CHANGE_SET
ABAP RAP – #ISOLATED
Demo use case
In this demo application we are going cover below requirements:
- Create Student management system where we can upload multiple documents for each student.
File Upload in any Business application is very common requirements, which was not available through ABAP RAP framework till the release of SAP BTP ABAP 2208.
As per our scenario we are going to create Student Record and will upload multiple documents for created Student.
Create persistent table for Student as below.
@EndUserText.label : 'Student Table Header'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zstudent_hdr_tab {
key client : abap.clnt not null;
key id : sysuuid_x16 not null;
firstname : abap.char(100);
lastname : abap.char(100);
age : abap.numc(4);
course : abap.char(50);
courseduration : abap.numc(4);
status : abap_boolean;
gender : abap.char(1);
dob : abap.dats;
lastchangedat : timestampl;
locallastchangedat : timestampl;
}
Create Persistent table for Attachments for Students
@EndUserText.label : 'Attachment Table'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table zstudent_att_tab {
key client : abap.clnt not null;
key attach_id : char32 not null;
id : sysuuid_x16 not null;
comments : char30;
attachment : zattachment1;
mimetype : char128;
filename : char128;
}
We are seeing field with name attachment of type zattachment1. Data type of attachment is very Important and since we are going to save file or Binary data or raw data in this field the field type must be RAWSTRING with length 0.
Length 0 is not mandatory but if length is not 0 then there will be restriction on the size of file that can be uploaded. 0 length means big files can be uploaded with no file size restriction.
Interface View for Student Header
Create Interface views for both Student and Attachments table.
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Interface View Entity for Student'
define root view entity zstudent_hdr_tab_I as select from zstudent_hdr_tab
composition[1..*] of zstudent_att_tab_i as _Attachments
{
@EndUserText.label: 'Student ID'
key zstudent_hdr_tab.id as Id,
@EndUserText.label: 'First Name'
zstudent_hdr_tab.firstname as Firstname,
@EndUserText.label: 'Last Name'
zstudent_hdr_tab.lastname as Lastname,
@EndUserText.label: 'Age'
zstudent_hdr_tab.age as Age,
@EndUserText.label: 'Course'
zstudent_hdr_tab.course as Course,
@EndUserText.label: 'Course Duration'
zstudent_hdr_tab.courseduration as Courseduration,
@EndUserText.label: 'Status'
zstudent_hdr_tab.status as Status,
@EndUserText.label: 'Gender'
zstudent_hdr_tab.gender as Gender,
@EndUserText.label: 'DOB'
zstudent_hdr_tab.dob as Dob,
zstudent_hdr_tab.lastchangedat as Lastchangedat,
zstudent_hdr_tab.locallastchangedat as Locallastchangedat,
_Attachments // Make association public
}
Interface View for Attachment Header
@semantics.LatgeObject is used to add file upload option on Student header Interface View.
contentDispositionpreference : This property value will decide If the file should be downloaded or should be opened in Browser’s tab when user clicks on File name once Uploaded.
#INLINE : File will be opened in Browder tab
#ATTACHMENT : File will be downloaded to users local machine
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'View for Attachment'
define view entity zstudent_att_tab_i as select from zstudent_att_tab
association to parent zstudent_hdr_tab_I as _Student
on $projection.Id = _Student.Id {
key zstudent_att_tab.attach_id as AttachId,
zstudent_att_tab.id as Id,
@EndUserText.label: 'Comments'
zstudent_att_tab.comments as Comments,
@EndUserText.label: 'Attachments'
@Semantics.largeObject:{
mimeType: 'Mimetype',
fileName: 'Filename',
contentDispositionPreference: #INLINE
}
zstudent_att_tab.attachment as Attachment,
@EndUserText.label: 'File Type'
zstudent_att_tab.mimetype as Mimetype,
@EndUserText.label: 'File Name'
zstudent_att_tab.filename as Filename,
_Student.Lastchangedat as LastChangedat,
_Student // Make association public
}
Projection View for Student Header Interface View
Create projection view and add UI annotations for Fiori application.
@EndUserText.label: 'Projection view for Header table'
@AccessControl.authorizationCheck: #NOT_REQUIRED
define root view entity zstudent_att_tab_p
provider contract transactional_query
as projection on zstudent_hdr_tab_I
{
@UI.facet: [{
id: 'StudentData',
purpose: #STANDARD,
label: 'Student Data',
type: #IDENTIFICATION_REFERENCE,
position: 10
},{
id: 'Upload',
purpose: #STANDARD,
label: 'Upload Attachments',
type: #LINEITEM_REFERENCE,
position: 20,
targetElement: '_Attachments'
}]
@UI: {
selectionField: [{ position: 10 }],
lineItem: [{ position: 10 }],
identification: [{ position: 10 }]
}
key Id,
@UI: {
lineItem: [{position: 20 }],
identification: [{position: 20 }]
}
Firstname,
@UI: {
lineItem: [{position: 30 }],
identification: [{position: 30 }]
}
Lastname,
@UI: {
lineItem: [{position: 40 }],
identification: [{position: 40 }]
}
Age,
@UI: {
lineItem: [{position: 50 }],
identification: [{position: 50 }]
}
Course,
@UI: {
lineItem: [{position: 60 }],
identification: [{position: 60 }]
}
Courseduration,
@UI: {
lineItem: [{position: 70 }],
identification: [{position: 70 }]
}
Status,
@UI: {
lineItem: [{position: 80 }],
identification: [{position: 80 }]
}
Gender,
@UI: {
lineItem: [{position: 90 }],
identification: [{position: 90 }]
}
Dob,
Lastchangedat,
Locallastchangedat,
/* Associations */
_Attachments : redirected to composition child zstudent_att_tabl_p
}
Projection View for Attachment Interface View
@EndUserText.label: 'Projection for Attachment'
@AccessControl.authorizationCheck: #NOT_REQUIRED
define view entity zstudent_att_tabl_p
as projection on zstudent_att_tab_i
{
@UI.facet: [{
id: 'StudentData',
purpose: #STANDARD,
label: 'Attachment Information',
type: #IDENTIFICATION_REFERENCE,
position: 10
}]
@UI: {
lineItem: [{ position: 10 }],
identification: [{ position: 10 }]
}
key AttachId,
@UI: {
lineItem: [{ position: 20 }],
identification: [{ position: 20 }]
}
Id,
@UI: {
lineItem: [{ position: 30 }],
identification: [{ position: 30 }]
}
Comments,
@UI: {
lineItem: [{ position: 40 }],
identification: [{ position: 40 }]
}
Attachment,
Mimetype,
Filename,
LastChangedat,
/* Associations */
_Student : redirected to parent zstudent_att_tab_p
}
Create behavior Definition for Student Header Interface View
Once Projection Views are ready, now we are going to create Behavior Definition. To add different actions to Object.
Right click on Student Header Interface View and create Behavior Definition. refer below pic.
In behavior Definition we are using Draft capability. Update behavior Definition for Student and Attachments as per below code.
managed implementation in class zbp_student_hdr_tab_i unique;
strict ( 1 ); with draft;
define behavior for zstudent_hdr_tab_I alias Student
persistent table zstudent_hdr_tab
draft table zstudent_h_d_tab
lock master
total etag Locallastchangedat
authorization master ( global )
etag master Lastchangedat
{
create;
update;
delete;
association _Attachments { create; with draft; }
field ( numbering : managed, readonly ) Id;
draft action Edit;
draft action Activate;
draft action Discard;
draft action Resume;
draft determine action Prepare;
mapping for zstudent_hdr_tab
{
Id = id;
Firstname = firstname;
Lastname = lastname;
Age = age;
Course = course;
Courseduration = courseduration;
Dob = dob;
Gender = gender;
Lastchangedat = lastchangedat;
Locallastchangedat = locallastchangedat;
Status = status;
}
}
define behavior for zstudent_att_tab_i alias Attachments
persistent table zstudent_att_tab
draft table zstudent_a_d_tab
lock dependent by _Student
authorization dependent by _Student
etag master LastChangedat
{
update;
delete;
field ( readonly ) Id;
association _Student { with draft; }
mapping for zstudent_att_tab{
AttachId = attach_id;
Attachment = attachment;
Comments = comments;
Filename = filename;
Id = id;
Mimetype = mimetype;
}
}
Save and Activate behavior Definition
Create Behavior Implementation of Behavior Definition
Behavior Implementation Class is ready. Since we are not performing any custom operation so no changes are needed at this point of time.
Create Behavior Definition for Student Header Projection View
Create Behavior Definition for Student Header Projection View as well. No changes are needed once created just Activate.
projection View behavior Definition will be created.
projection;
strict ( 1 );
use draft;
define behavior for zstudent_att_tab_p //alias <alias_name>
{
use create;
use update;
use delete;
use action Edit;
use action Activate;
use action Discard;
use action Resume;
use action Prepare;
use association _Attachments { create; with draft; }
}
define behavior for zstudent_att_tabl_p //alias <alias_name>
{
use update;
use delete;
use association _Student { with draft; }
}
Save and Activate behavior Definition
Create Service Definition to Expose both Projection Views
Select Attachment Projection View and create new Service Definition
@EndUserText.label: 'Service Defination'
define service ZSTUDENT_ATT_SD {
expose zstudent_att_tabl_p;
expose zstudent_att_tab_p;
}
Save and Activate behavior Definition
Create Service Bindings for created Service Definition
To create new Service Binding right click on Service Definition and select New Service Bindings
Must select binding Type as OData V4 – UI, since we want to have Create EDIT and Delete operations available along with Attachments Upload.
Add to Transport and click on Finish button.
Click on Activate Service Binding and once Activated we need to Publish new created Service Binding. Once Published then only Service URL will be available to be used to create Fiori Application.
Once created Service Bindings and Published it should look like below
Final application structure looks like below :
Run and Test Application for File Upload
Application Initial screen will look like below. with Action buttons to Create and Delete Records
Click on Create button to add new Student Record, below screen will be displayed. Update all required student Information and click on Create button on Upload Attachment Facet to upload Resume file.
Since Id field of Attachment is not an Auto generated field and Not null, in this case RAP Framework will display popup asking unique number for Attachment ID
Provide Comments for Attachment file and Use Upload Button to select file to Upload, once done click on Apply Button which will save file temporarily
Once done click on Save Button and File will be Uploaded and Saved for created Student Record
Upload another file. Multiple files are uploaded successfully
Notes:
- Service Binding Type must be OData V4 – UI.
- Attachment field type must be RAWSTRING.
- Attachment field data type length should be 0 otherwise there will be restriction on file size to be uploaded, 0 means no restriction.