RAP CDS Pattern: Vereinfachte Architektur mit Table Entities

Kategorie
RAP
Veröffentlicht
Autor
Johannes

Das klassische RAP erfordert mehrere Schichten: Datenbanktabelle, Interface CDS View, Projection View, Behavior Definition und Service Definition. Das RAP CDS Pattern (auch CDS-only Pattern genannt) vereinfacht diese Architektur erheblich - mit Table Entities als zentralem Element.

Das Problem: Zu viele Objekte

Für eine einfache CRUD-Anwendung benötigt der klassische RAP-Stack:

1. Datenbanktabelle (ZFLIGHT_BOOK)
2. Interface CDS View (ZI_FlightBooking)
3. Projection CDS View (ZC_FlightBooking)
4. Behavior Definition (ZI_FlightBooking)
5. Behavior Implementation (ZBP_I_FLIGHTBOOKING)
6. Service Definition (ZUI_FLIGHTBOOKING)
7. Service Binding (ZUI_FLIGHTBOOKING_O4)

Für ein einfaches Datenobjekt sind das sieben Entwicklungsobjekte - viel Overhead für CRUD-Operationen.

Die Lösung: Table Entities

Mit Table Entities (eingeführt mit ABAP Cloud 2024) wird die Tabelle selbst zum Entity:

1. Table Entity (ZI_FlightBooking) - Tabelle + View in einem
2. Behavior Definition (ZI_FlightBooking)
3. Service Definition (ZUI_FLIGHTBOOKING)
4. Service Binding (ZUI_FLIGHTBOOKING_O4)

Nur noch vier Objekte - und oft ist keine Behavior Implementation nötig.

Klassisch vs. CDS Pattern

AspektKlassischer RAP StackCDS Pattern
Objekte5-73-4
TabellendefinitionSeparates DDLIn Table Entity
Interface ViewEigene CDS ViewTable Entity selbst
Projection ViewErforderlichOptional
FlexibilitätMaximalStandard-CRUD
Berechnete FelderJaNein
AliaseFrei wählbarIdentisch mit Spalte
Empfohlen fürKomplexe BOsEinfache CRUD

Vollständiges Beispiel: Flugbuchung

Schritt 1: Table Entity definieren

Das Table Entity kombiniert Tabellendefinition und CDS View:

@EndUserText.label: 'Flugbuchung'
@AbapCatalog.enhancement.category: #NOT_EXTENSIBLE
@AbapCatalog.tableCategory: #TRANSPARENT
@AbapCatalog.deliveryClass: #A
@AbapCatalog.dataMaintenance: #RESTRICTED
define table entity zi_flightbooking {
key client : abap.clnt not null;
key booking_id : abap.numc(10) not null;
// Geschäftsdaten
flight_date : abap.dats;
carrier_id : abap.char(3);
connection_id : abap.numc(4);
customer_id : abap.numc(10);
// Buchungsdetails
@Semantics.amount.currencyCode: 'zi_flightbooking.currency_code'
flight_price : abap.curr(15,2);
currency_code : abap.cuky;
booking_status : abap.char(1);
// Administrative Felder (wichtig für RAP!)
@Semantics.user.createdBy: true
created_by : abap.uname;
@Semantics.systemDateTime.createdAt: true
created_at : abap.utclong;
@Semantics.user.lastChangedBy: true
last_changed_by : abap.uname;
@Semantics.systemDateTime.lastChangedAt: true
last_changed_at : abap.utclong;
@Semantics.systemDateTime.localInstanceLastChangedAt: true
local_last_changed : abap.utclong;
}

Wichtig: Die Semantics-Annotationen für administrative Felder ermöglichen automatisches Befüllen durch das RAP-Framework.

Schritt 2: Behavior Definition

Die Behavior Definition referenziert direkt das Table Entity:

managed implementation in class zbp_i_flightbooking unique;
strict ( 2 );
define behavior for zi_flightbooking alias FlightBooking
lock master
authorization master ( instance )
etag master local_last_changed
{
// Standard CRUD - Framework übernimmt alles
create;
update;
delete;
// Felder schreibgeschützt
field ( readonly ) booking_id;
field ( readonly ) created_by, created_at, last_changed_by, last_changed_at;
field ( readonly : update ) carrier_id, connection_id, flight_date;
// Automatische Nummernvergabe
field ( numbering : managed ) booking_id;
// Einfache Actions
action confirmBooking result [1] $self;
action cancelBooking result [1] $self;
// Validierung
validation validateFlightDate on save { field flight_date; }
validation validateCustomer on save { field customer_id; }
// Determination für Status
determination setInitialStatus on modify { create; }
// Mapping - identisch da Table Entity
mapping for zi_flightbooking corresponding;
}

Schritt 3: Service Definition

@EndUserText.label: 'Flugbuchung Service'
define service ZUI_FLIGHTBOOKING {
expose zi_flightbooking as FlightBooking;
}

Schritt 4: Service Binding

Name: ZUI_FLIGHTBOOKING_O4
Service: ZUI_FLIGHTBOOKING
Binding Type: OData V4 - UI

Nach dem Aktivieren und Veröffentlichen steht die Fiori Elements App bereit.

Behavior Implementation (optional)

Für Actions und Validierungen benötigen Sie eine Implementierungsklasse:

CLASS zbp_i_flightbooking DEFINITION PUBLIC ABSTRACT FINAL
FOR BEHAVIOR OF zi_flightbooking.
ENDCLASS.
CLASS zbp_i_flightbooking IMPLEMENTATION.
ENDCLASS.
CLASS lhc_flightbooking DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS:
confirmBooking FOR MODIFY
IMPORTING keys FOR ACTION FlightBooking~confirmBooking
RESULT result,
cancelBooking FOR MODIFY
IMPORTING keys FOR ACTION FlightBooking~cancelBooking
RESULT result,
validateFlightDate FOR VALIDATE ON SAVE
IMPORTING keys FOR FlightBooking~validateFlightDate,
validateCustomer FOR VALIDATE ON SAVE
IMPORTING keys FOR FlightBooking~validateCustomer,
setInitialStatus FOR DETERMINE ON MODIFY
IMPORTING keys FOR FlightBooking~setInitialStatus.
ENDCLASS.
CLASS lhc_flightbooking IMPLEMENTATION.
METHOD confirmBooking.
" Status auf 'Bestätigt' setzen
MODIFY ENTITIES OF zi_flightbooking IN LOCAL MODE
ENTITY FlightBooking
UPDATE FIELDS ( booking_status )
WITH VALUE #( FOR key IN keys
( %tky = key-%tky
booking_status = 'C' ) ).
" Ergebnis zurückgeben
READ ENTITIES OF zi_flightbooking IN LOCAL MODE
ENTITY FlightBooking
ALL FIELDS WITH CORRESPONDING #( keys )
RESULT DATA(bookings).
result = VALUE #( FOR booking IN bookings
( %tky = booking-%tky
%param = booking ) ).
ENDMETHOD.
METHOD cancelBooking.
MODIFY ENTITIES OF zi_flightbooking IN LOCAL MODE
ENTITY FlightBooking
UPDATE FIELDS ( booking_status )
WITH VALUE #( FOR key IN keys
( %tky = key-%tky
booking_status = 'X' ) ).
READ ENTITIES OF zi_flightbooking IN LOCAL MODE
ENTITY FlightBooking
ALL FIELDS WITH CORRESPONDING #( keys )
RESULT DATA(bookings).
result = VALUE #( FOR booking IN bookings
( %tky = booking-%tky
%param = booking ) ).
ENDMETHOD.
METHOD validateFlightDate.
READ ENTITIES OF zi_flightbooking IN LOCAL MODE
ENTITY FlightBooking
FIELDS ( flight_date )
WITH CORRESPONDING #( keys )
RESULT DATA(bookings).
LOOP AT bookings INTO DATA(booking).
IF booking-flight_date < cl_abap_context_info=>get_system_date( ).
APPEND VALUE #(
%tky = booking-%tky
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'Flugdatum muss in der Zukunft liegen' )
%element-flight_date = if_abap_behv=>mk-on
) TO reported-flightbooking.
APPEND VALUE #( %tky = booking-%tky ) TO failed-flightbooking.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD validateCustomer.
" Kundenvalidierung implementieren
READ ENTITIES OF zi_flightbooking IN LOCAL MODE
ENTITY FlightBooking
FIELDS ( customer_id )
WITH CORRESPONDING #( keys )
RESULT DATA(bookings).
LOOP AT bookings INTO DATA(booking).
IF booking-customer_id IS INITIAL.
APPEND VALUE #(
%tky = booking-%tky
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'Kunde muss angegeben werden' )
%element-customer_id = if_abap_behv=>mk-on
) TO reported-flightbooking.
APPEND VALUE #( %tky = booking-%tky ) TO failed-flightbooking.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD setInitialStatus.
READ ENTITIES OF zi_flightbooking IN LOCAL MODE
ENTITY FlightBooking
FIELDS ( booking_status )
WITH CORRESPONDING #( keys )
RESULT DATA(bookings).
MODIFY ENTITIES OF zi_flightbooking IN LOCAL MODE
ENTITY FlightBooking
UPDATE FIELDS ( booking_status )
WITH VALUE #( FOR booking IN bookings
WHERE ( booking_status IS INITIAL )
( %tky = booking-%tky
booking_status = 'O' ) ).
ENDMETHOD.
ENDCLASS.

Aktuelle Limitierungen

Das CDS Pattern ist leistungsfähig, hat aber Einschränkungen (Stand Februar 2026):

ENUMs nicht direkt unterstützt

" ❌ Funktioniert NICHT in Table Entities
booking_status : zbooking_status_enum;
" ✅ Workaround: CHAR-Feld mit Value Help
booking_status : abap.char(1);

Die Enum-Werte müssen über eine separate Value Help oder CDS Annotation bereitgestellt werden.

Draft-Handling eingeschränkt

" ❌ Draft erfordert klassischen RAP Stack mit Projection View
with draft;
" ✅ Im CDS Pattern: Nur ohne Draft möglich
" Table Entity unterstützt kein draft table

Für Draft-Funktionalität benötigen Sie weiterhin den klassischen RAP-Aufbau mit Interface View und Projection View.

Keine berechneten Felder

" ❌ In Table Entity NICHT möglich
calculated_field : abap.char(10) = concat(carrier_id, connection_id);
" ✅ Klassische CDS View
define view entity ZI_FlightBooking as select from zflight_book {
key booking_id,
concat(carrier_id, connection_id) as FlightNumber
}

Keine Assoziationen zu anderen Table Entities

" ❌ Table Entity kann keine Assoziationen definieren
association [1..1] to zi_customer as _Customer;
" ✅ Workaround: Separate CDS View für Assoziationen

Wann welches Pattern?

CDS Pattern empfohlen

  • Einfache CRUD-Anwendungen ohne komplexe Beziehungen
  • Stammdatenpflege (Kunden, Produkte, Konfigurationen)
  • Schnelle Prototypen und MVPs
  • Anwendungen ohne Draft-Anforderung
  • Standalone Entities ohne Hierarchien

Klassischer RAP Stack empfohlen

  • Komplexe Business Objects mit Parent-Child-Hierarchien
  • Draft-Handling erforderlich
  • Berechnete Felder in der View nötig
  • Feldaliase für bessere Lesbarkeit
  • Assoziationen zwischen Entities
  • Unterschiedliche Projections für verschiedene Apps

Migration: Von CDS Pattern zu klassischem Stack

Wenn Anforderungen wachsen, können Sie migrieren:

" 1. Table Entity bleibt als Datenbanktabelle erhalten
" (Umbenennen zu ztable_flightbooking)
" 2. Neue Interface CDS View erstellen
define root view entity ZI_FlightBooking
as select from ztable_flightbooking
{
key booking_id as BookingId,
" ... weitere Felder mit Aliasen
}
" 3. Behavior Definition anpassen
define behavior for ZI_FlightBooking
persistent table ztable_flightbooking
" ...

Fazit

Das RAP CDS Pattern reduziert den Entwicklungsaufwand für einfache RAP-Anwendungen erheblich:

KriteriumCDS PatternKlassisch
Entwicklungsobjekte3-45-7
EinarbeitungszeitKürzerLänger
FlexibilitätStandardMaximum
Draft SupportNeinJa
AssoziationenEingeschränktVoll

Für Neueinsteiger und einfache CRUD-Anwendungen ist das CDS Pattern der schnellste Weg zur funktionierenden Fiori App. Bei wachsenden Anforderungen lässt sich auf den klassischen Stack migrieren.

Weiterführende Artikel: RAP Grundlagen für das klassische Pattern, Tabellen in ABAP Cloud für Tabellendefinitionen, RAP Managed vs Unmanaged für die Architekturentscheidung und CDS Views für komplexe Datenmodelle.