RAP - Complex entity
Let's look at a RAP application with two entities and how they are connected. We mainly focus on the differences.
Table of contents
A while ago we looked at a simple entity and how to build it entirely on top of RAP. In this article, we'll take a look at what the differences are when building more than one entity into an application. If you want to know more about the structure of simple entities, it is best to start at the beginning of the series.
Introduction
We had already looked closely at how to build a RAP application using an entity and what we need. In this small series, we will look at building complex applications by merging invoices and positions in one application. We will again work with the data model on our CDS series.
Data model
We want to bring the two entities invoice and item together into one app and make it editable, the data model looks like this:
We need the entity for material because the unit of measure is required and this is only available for the material. As always, we create an interface layer and put the consumption layer on top for the application.
CDS
The first adaptation already exists at the data modeling level. We need links between the entities because we later want to navigate from the invoices to the items and because these two objects belong together. Let's take a closer look at the two layers.
Interface
At the interface level, we connect the invoices to the positions. To do this, we create a "composition" from the root node in the direction of the position, the view looks like this:
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Interface for ZBS_DMO_INVOICE'
define root view entity ZBS_R_RAPCInvoice
as select from zbs_dmo_invoice
composition [0..*] of ZBS_I_RAPCPosition as _Position
{
key document as Document,
doc_date as DocDate,
doc_time as DocTime,
partner as Partner,
_Position
}
At the position level, we now have to create an "Association To Parent" to make it clear that there is an upward relationship here. The second association is for the entity we need for the data.
@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Interface for ZBS_DMO_POSITION'
define view entity ZBS_I_RAPCPosition
as select from zbs_dmo_position
association to parent ZBS_R_RAPCInvoice as _Invoice on $projection.Document = _Invoice.Document
association [1] to ZBS_I_RAPCMaterial as _Material on $projection.Material = _Material.Material
{
key document as Document,
key pos_number as PositionNumber,
material as Material,
@Semantics.quantity.unitOfMeasure : 'Unit'
quantity as Quantity,
_Material.StockUnit as Unit,
price as Price,
currency as Currency,
_Invoice
}
Consumption
It looks similar at the consumption level, but here the relationships are defined differently. To do this, we add a "Redirect to Composition Child" in the root entity after the association.
@EndUserText.label: 'Consumption for ZBS_R_RAPCINVOICE'
@AccessControl.authorizationCheck: #NOT_REQUIRED
@Metadata.allowExtensions: true
define root view entity ZBS_C_RAPCInvoice
provider contract transactional_query
as projection on ZBS_R_RAPCInvoice as Invoice
{
key Document,
DocDate,
DocTime,
Partner,
_Position : redirected to composition child ZBS_C_RAPCPosition
}
For the items we need a "Redirect To Parent", i.e. to the invoice. The relationships are used later in the service for navigating between the entities.
@EndUserText.label: 'Consumption for ZBS_I_RAPCPOSITION'
@AccessControl.authorizationCheck: #NOT_REQUIRED
@Metadata.allowExtensions: true
define view entity ZBS_C_RAPCPosition
as projection on ZBS_I_RAPCPosition as Position
{
key Document,
key PositionNumber,
Material,
Quantity,
Unit,
Price,
Currency,
_Invoice : redirected to parent ZBS_C_RAPCInvoice
}
Behavior definition
Now what about managing behavior implementation? Here you need two definitions, one for each entity. Special features to consider here would be:
- The item is created via the association of the invoice and not directly via the item.
- Associations are announced in the entities.
- Blocking and authorizing on the data of the item is done via the invoice.
- The behavior implementation can be implemented per entity or via a class in the head of the behavior definition.
The definition of behavior is as follows:
managed implementation in class zbp_bs_rapcinvoice unique;
strict ( 1 );
define behavior for ZBS_R_RAPCInvoice alias Invoice
persistent table zbs_dmo_invoice
lock master
authorization master ( instance )
{
create;
update;
delete;
field ( readonly:update ) Document;
association _Position { create; }
mapping for zbs_dmo_invoice
{
Document = document;
Partner = partner;
DocDate = doc_date;
DocTime = doc_time;
}
}
define behavior for ZBS_I_RAPCPosition alias Position
persistent table zbs_dmo_position
lock dependent by _Invoice
authorization dependent by _Invoice
{
update;
delete;
field ( readonly ) Document;
field ( readonly:update ) PositionNumber;
association _Invoice;
mapping for zbs_dmo_position
{
Document = document;
PositionNumber = pos_number;
Material = material;
Price = price;
Quantity = quantity;
Currency = currency;
}
}
However, you can best see how the associations are handled in the projection of the behavior definition:
projection;
strict ( 1 );
define behavior for ZBS_C_RAPCInvoice alias Invoice
{
use create;
use update;
use delete;
use association _Position { create; }
}
define behavior for ZBS_C_RAPCPosition alias Position
{
use update;
use delete;
use association _Invoice;
}
Service
The service definition and the service binding can then be created as usual, both entities should be given so that access is available for them. After creating the binding, the two entities should be visible, as well as the connections between them.
App
The application itself has no design, fields or restriction options. As before, you can use the Fiori Elements Preview to define a basic layout, at least to be able to test it once. A navigation to the positions is currently not possible, for this we first have to create the UI annotations.
GitHub
As always, we have made the changes available in the GitHub repository. The customization commit created new objects in the ZBS_DEMO_RAP_COMPLEXE package if you don't want to search everything.
Conclusion
The structure of the application is similar to our simple application, but there are a few things to note, for example that the individual entities are linked to each other. As usual, you can find all changes in the GitHub repository.