Practical aspects on BOPF-based Development in the S/4HANA context
In my perception the BOPF Framework has benefited from quite a popularity boost with the release of the S/4HANA Programming Model, in which it plays a central role. When it comes to “pure” BOPF-based development SCN already provides valuable in-depth information through @oliverjaegle‘s posts. With the new programming model however Gateway/SADL becomes the standard way of consuming BOPF objects. This implies a slight shift in the developer mindset (due to the stateless nature of the the services and other specifics of the OData protocol).
Wouldn’t it be great if we had some updated guidelines for BOPF-based development, which consider the specifics of the S/4 Programming Model? With this in mind and browsing through Oliver’s posts once again, I have written down a few notes on some of the topics which could be part of such an updated BOPF guideline.
The list is by far not complete, however it’s a starting point for anyone transitioning from “classical” BOPF-based development to the S/4 Programming Model. Here it is:
Part 1: general structural aspects & Part 1 Addendum: Other associations
Transient fields are not available for consumption via Gateway, as SADL pushes the query directly to the database. In some cases these could be replaced by a calculated column of a CDS consumption view.
Human readable alternative keys for your BOPF nodes are a must, as they can then be used for addressing Gateway Entities (otherwise you will be stuck with the generated GUIDs)
Associations are essential when consuming BOPF through SADL, as these are mapped to navigation properties on the Gateway Entities. Only declarative (not implemented) associations are supported, as the SADL runtime needs to be able to generate the dynamic SQL queries out of them.
Part 2: Consumption of a BO using CRUD services
Consumption of BOPF data via SADL occurs very differently depending on the access-type:
- Write access: uses the BOPF Service Manager API
- Read access: SELECT statements are dynamically generated by the SADL runtime and pushed to the database, bypassing the BOPF buffer.
Due to the implicit query pushdown, there is less utility for BOPF queries to a developer in the new programming model (although technically the framework still needs them).
One other place where they are still needed is for the querying of data within the BOPF test transaction (BOBT). However, instead of using BOBT you might be better of testing using an OData client (see also part 8)
Part 3: Locking and authorization management
Declarative definition of authority checks is supported out of the box for both read & write access, and this will be sufficient for most use cases. However, things can get somewhat more complicated if you need some custom authority checks, as these need to be implemented twice:
- Write access: overwriting of the BOPF authority check library class
- Read access: redefining the SADL query condition provider, to generate the required WHERE-clauses dynamically at runtime (DCL expressions are not yet powerful enough to support complex scenarios)
Part 5: Properties
Properties defined on the BOPF model are not exposed to Gateway (and the Fiori frontend). Instead, with the S4 programming model the driving force when it comes to field properties are annotations defined on the CDS model (see field control). These are both exposed to the Fiori UI and implicitly set as static properties on the generated BOPF BOs.
This leaves open the question of handling dynamic properties(e.g. setting a field read-only based on user input). Afaik there is no out-of-the-box support for this yet. However for this purpose one could expect the BOPF property determinations to be integrated into the programming model.
Part 6: Validations
While validations are perhaps the most commonly used BOPF artifact, I believe the new consumption model (via SADL) combined with the changes in the BOPF design-time (Eclipse-based editor) can be the cause of some confusion around choosing the correct validation type for the job.
I would like to tackle this in a separate blog post and answer questions like: What is the correspondence between validation configuration in Eclipse vs. BOBX? When exactly is a certain validation type triggered? When does a validation cancel a transaction?
Part 8: A modification roundtrip
Transitioning to the S/4 model requires every backend developer to become comfortable with OData and start thinking stateless. The application backend should rather be tested using an OData client than BOBT in order to assure consistent results. Mastering some details of the OData protocol ($expands, deep inserts, $batch requests) and getting to know the limitations of your Gateway/SADL/BOPF stack (e.g. content-ID-referencing not supported) is a must.
Thank you for disclosing very important information on the topic! There is so much info about classic BOPF and just a little about CDS-based ones.
But if I try to associate to another CDS-based BO as a child node (with annotation @ObjectModel.association.type: [#TO_COMPOSITION_CHILD]) SADL returns an error “View is already used in Business Object <BO name>”, and if l put an association without annotation, SADL doesn’t generate BO association for it.
If I declare an association in BOPF editor in Eclipce, it work fine, but each time I regenerate root CDS for this BO, all such associations break down, and I have to reset them.
Do you know the “true way” to declare external (cross-BO) associations in CDS?
I haven't tried this scenario, I used to do the modelling in BOPF directly in these cases.
Is it mandatory for you to have a cross-BO association in BOPF? I assume the CDS-based association should be sufficient to make it accesible via OData (at least for read-access)
Yes a cross-BO association is mandatory in my case, because I have to integrate standard BO as a node into my custom BO and change them both simultaneously via Fiori app.
Now I'm doing it manually in determination of my custom BO (I've also created a "clone" node with the values, which being changed in app and then syncronized with standard BO values). But in "normal" BOPF it's possible to include one BO into another as a node.
Did you get the new BOPF node association to a standard CDS-based BO by #TO_COMPOSITION_CHILD annotation? I was trying to do the same approach but had not luck so far