RAP CDS Pattern: Arquitectura Simplificada con Table Entities

Kategorie
RAP
Veröffentlicht
Autor
Johannes

El RAP clásico requiere múltiples capas: tabla de base de datos, Interface CDS View, Projection View, Behavior Definition y Service Definition. El RAP CDS Pattern (también llamado CDS-only Pattern) simplifica significativamente esta arquitectura - con Table Entities como elemento central.

El Problema: Demasiados Objetos

Para una aplicación CRUD simple, el stack RAP clásico requiere:

1. Tabla de base de datos (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)

Para un objeto de datos simple, estos son siete objetos de desarrollo - mucho overhead para operaciones CRUD.

La Solución: Table Entities

Con Table Entities (introducidas con ABAP Cloud 2024), la tabla misma se convierte en la entidad:

1. Table Entity (ZI_FlightBooking) - Tabla + View en uno
2. Behavior Definition (ZI_FlightBooking)
3. Service Definition (ZUI_FLIGHTBOOKING)
4. Service Binding (ZUI_FLIGHTBOOKING_O4)

Solo cuatro objetos - y a menudo no se necesita Behavior Implementation.

Clásico vs. CDS Pattern

AspectoStack RAP ClásicoCDS Pattern
Objetos5-73-4
Definición de tablaDDL separadoEn Table Entity
Interface ViewCDS View propiaTable Entity mismo
Projection ViewRequeridaOpcional
FlexibilidadMáximaCRUD estándar
Campos calculadosNo
AliasesLibre elecciónIdéntico a columna
Recomendado paraBOs complejosCRUD simple

Ejemplo Completo: Reserva de Vuelo

Paso 1: Definir Table Entity

El Table Entity combina la definición de tabla y CDS View:

@EndUserText.label: 'Reserva de Vuelo'
@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;
// Datos de negocio
flight_date : abap.dats;
carrier_id : abap.char(3);
connection_id : abap.numc(4);
customer_id : abap.numc(10);
// Detalles de reserva
@Semantics.amount.currencyCode: 'zi_flightbooking.currency_code'
flight_price : abap.curr(15,2);
currency_code : abap.cuky;
booking_status : abap.char(1);
// Campos administrativos (¡importantes para 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;
}

Importante: Las anotaciones Semantics para campos administrativos permiten el llenado automático por el framework RAP.

Paso 2: Behavior Definition

La Behavior Definition referencia directamente el 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
{
// CRUD estándar - El framework se encarga de todo
create;
update;
delete;
// Campos de solo lectura
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;
// Numeración automática
field ( numbering : managed ) booking_id;
// Actions simples
action confirmBooking result [1] $self;
action cancelBooking result [1] $self;
// Validación
validation validateFlightDate on save { field flight_date; }
validation validateCustomer on save { field customer_id; }
// Determination para estado
determination setInitialStatus on modify { create; }
// Mapping - idéntico porque es Table Entity
mapping for zi_flightbooking corresponding;
}

Paso 3: Service Definition

@EndUserText.label: 'Servicio de Reserva de Vuelo'
define service ZUI_FLIGHTBOOKING {
expose zi_flightbooking as FlightBooking;
}

Paso 4: Service Binding

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

Después de activar y publicar, la aplicación Fiori Elements está lista.

Behavior Implementation (opcional)

Para Actions y validaciones, necesita una clase de implementación:

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.
" Establecer estado a 'Confirmado'
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' ) ).
" Devolver resultado
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 = 'La fecha del vuelo debe estar en el futuro' )
%element-flight_date = if_abap_behv=>mk-on
) TO reported-flightbooking.
APPEND VALUE #( %tky = booking-%tky ) TO failed-flightbooking.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD validateCustomer.
" Implementar validación de cliente
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 = 'Se debe especificar el cliente' )
%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.

Limitaciones Actuales

El CDS Pattern es potente, pero tiene restricciones (estado febrero 2026):

ENUMs no soportados directamente

" ❌ NO funciona en Table Entities
booking_status : zbooking_status_enum;
" ✅ Solución alternativa: campo CHAR con Value Help
booking_status : abap.char(1);

Los valores Enum deben proporcionarse a través de un Value Help separado o anotación CDS.

Draft Handling limitado

" ❌ Draft requiere stack RAP clásico con Projection View
with draft;
" ✅ En CDS Pattern: Solo posible sin Draft
" Table Entity no soporta draft table

Para funcionalidad Draft, todavía necesita la estructura RAP clásica con Interface View y Projection View.

Sin campos calculados

" ❌ NO es posible en Table Entity
calculated_field : abap.char(10) = concat(carrier_id, connection_id);
" ✅ CDS View clásica
define view entity ZI_FlightBooking as select from zflight_book {
key booking_id,
concat(carrier_id, connection_id) as FlightNumber
}

Sin asociaciones a otros Table Entities

" ❌ Table Entity no puede definir asociaciones
association [1..1] to zi_customer as _Customer;
" ✅ Solución alternativa: CDS View separada para asociaciones

¿Cuándo usar qué patrón?

CDS Pattern recomendado

  • Aplicaciones CRUD simples sin relaciones complejas
  • Mantenimiento de datos maestros (Clientes, Productos, Configuraciones)
  • Prototipos rápidos y MVPs
  • Aplicaciones sin requisito de Draft
  • Entidades independientes sin jerarquías

Stack RAP Clásico recomendado

  • Business Objects complejos con jerarquías Parent-Child
  • Draft Handling requerido
  • Campos calculados necesarios en la View
  • Aliases de campo para mejor legibilidad
  • Asociaciones entre Entities
  • Diferentes Projections para distintas apps

Migración: De CDS Pattern a Stack Clásico

Si los requisitos crecen, puede migrar:

" 1. Table Entity permanece como tabla de base de datos
" (Renombrar a ztable_flightbooking)
" 2. Crear nueva Interface CDS View
define root view entity ZI_FlightBooking
as select from ztable_flightbooking
{
key booking_id as BookingId,
" ... más campos con aliases
}
" 3. Ajustar Behavior Definition
define behavior for ZI_FlightBooking
persistent table ztable_flightbooking
" ...

Conclusión

El RAP CDS Pattern reduce significativamente el esfuerzo de desarrollo para aplicaciones RAP simples:

CriterioCDS PatternClásico
Objetos de desarrollo3-45-7
Tiempo de aprendizajeMás cortoMás largo
FlexibilidadEstándarMáxima
Soporte DraftNo
AsociacionesLimitadasCompletas

Para principiantes y aplicaciones CRUD simples, el CDS Pattern es el camino más rápido hacia una aplicación Fiori funcional. Con requisitos crecientes, se puede migrar al stack clásico.

Artículos relacionados: Fundamentos de RAP para el patrón clásico, Tablas en ABAP Cloud para definiciones de tablas, RAP Managed vs Unmanaged para la decisión de arquitectura y CDS Views para modelos de datos complejos.