Draft Handling en RAP: Almacenamiento Intermedio para Workflows Complejos

Kategorie
RAP
Veröffentlicht
Autor
Johannes

Draft Handling permite a los usuarios guardar cambios en Business Objects de forma intermedia, sin escribirlos inmediatamente en la base de datos. Esto es especialmente importante para formularios de entrada complejos en aplicaciones Fiori. Con Draft Handling, los usuarios pueden interrumpir su trabajo, continuar en un momento posterior y solo entonces activar los cambios cuando todas las entradas estén completas y validadas.

En este articulo aprenderas como funciona Draft Handling en RAP, como crear CDS Views y Behavior Definitions habilitadas para draft, y que Draft Actions estan disponibles para workflows tipicos.

El Concepto Draft: Instancias Active vs. Draft

El concepto central en Draft Handling es la distincion entre instancias activas e instancias draft:

  • Instancias Activas (Active Entities): Los datos persistentes en la tabla de base de datos. Representan el estado actual y valido del Business Object y son visibles para todos los usuarios.

  • Instancias Draft (Draft Entities): Copias de trabajo temporales que se almacenan en una tabla Draft separada. Un Draft solo es visible para el usuario que lo edita y contiene cambios aun no validados o incompletos.

El ciclo de vida de un Draft tipicamente se ve asi:

  1. Edit: El usuario inicia la edicion -> El sistema crea una copia Draft
  2. Modify: El usuario cambia datos -> Los cambios se guardan automaticamente en el Draft
  3. Prepare: El sistema ejecuta validaciones -> Los errores se muestran, pero el Draft permanece
  4. Activate: El usuario activa -> El Draft se convierte en instancia activa, la entrada Draft se elimina

Alternativamente, el usuario puede elegir Discard en cualquier momento para descartar el Draft sin modificar la instancia activa.

¿Cuando necesito Draft?

Draft Handling es util para:

  • Formularios de entrada complejos con muchos campos
  • Workflows de multiples pasos, donde los usuarios quieren guardar de forma intermedia
  • Transacciones de larga duracion, que no se completan en una sesion
  • Validaciones, que solo deben ejecutarse en la activacion

Draft vs. Non-Draft Escenarios

AspectoDraftNon-Draft
AlmacenamientoTabla Draft separadaDirectamente en tabla de base de datos
Guardar intermedioSi, automaticamenteNo
ValidacionEn Prepare/ActivateEn cada Save
ComplejidadMayorMenor
Fiori-UXMejorada (Auto-Save)Estandar
Caso de usoFormularios complejosApps CRUD simples

Escenario Non-Draft (Estandar)

managed implementation in class zbp_i_travel unique;
strict ( 2 );
define behavior for ZI_Travel alias Travel
persistent table ztravel
lock master
authorization master ( instance )
etag master LastChangedAt
{
create;
update;
delete;
}

Escenario Draft

managed implementation in class zbp_i_travel unique;
strict ( 2 );
with draft;
define behavior for ZI_Travel alias Travel
persistent table ztravel
draft table zdraft_travel
lock master total etag LastChangedAt
authorization master ( instance )
etag master LastChangedAt
{
create;
update;
delete;
draft action Edit;
draft action Activate optimized;
draft action Discard;
draft action Resume;
draft determine action Prepare;
}

Exclusive vs. Shared Locks

RAP soporta dos modos de Lock para escenarios Draft:

Tipo de LockDescripcionCaso de uso
ExclusiveSolo un usuario puede editar el objetoEstandar para datos criticos
SharedMultiples usuarios pueden crear DraftsEscenarios colaborativos

Exclusive Lock (Estandar)

Con Exclusive Lock solo un usuario puede editar un Business Object simultaneamente:

define behavior for ZI_Travel alias Travel
persistent table ztravel
draft table zdraft_travel
lock master total etag LastChangedAt
authorization master ( instance )
{
// Exclusive Lock ist der Standard
// Nur ein Draft pro Instanz erlaubt
}

Shared Lock

Con Shared Lock multiples usuarios pueden crear Drafts independientes:

define behavior for ZI_Travel alias Travel
persistent table ztravel
draft table zdraft_travel
lock master total etag LastChangedAt
authorization master ( instance )
late numbering
{
// Shared Draft: Mehrere Benutzer können
// verschiedene Versionen bearbeiten
with unmanaged save;
}

Crear CDS Views habilitadas para Draft

Para usar Draft Handling, sus CDS Views deben cumplir ciertos requisitos. El requisito mas importante es un campo Total ETag que rastrea los cambios en toda la entidad.

Interface View con soporte Draft

@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Travel - Interface View'
define root view entity ZI_Travel
as select from ztravel
association [0..*] to ZI_Booking as _Booking
on $projection.TravelUUID = _Booking.TravelUUID
{
key travel_uuid as TravelUUID,
travel_id as TravelId,
agency_id as AgencyId,
customer_id as CustomerId,
begin_date as BeginDate,
end_date as EndDate,
@Semantics.amount.currencyCode: 'CurrencyCode'
total_price as TotalPrice,
currency_code as CurrencyCode,
description as Description,
overall_status as OverallStatus,
// Administrative Felder
@Semantics.user.createdBy: true
created_by as CreatedBy,
@Semantics.systemDateTime.createdAt: true
created_at as CreatedAt,
@Semantics.user.lastChangedBy: true
last_changed_by as LastChangedBy,
@Semantics.systemDateTime.lastChangedAt: true
last_changed_at as LastChangedAt,
// Wichtig für Draft: Total ETag für Concurrency Control
@Semantics.systemDateTime.localInstanceLastChangedAt: true
local_last_changed_at as LocalLastChangedAt,
// Associations
_Booking
}

El campo LocalLastChangedAt con la anotacion @Semantics.systemDateTime.localInstanceLastChangedAt se usa como Total ETag. Permite al framework RAP detectar conflictos en accesos concurrentes.

Projection View para Draft

La Projection View debe exponer los campos relevantes para Draft:

@AccessControl.authorizationCheck: #NOT_REQUIRED
@EndUserText.label: 'Travel - Projection View'
@Metadata.allowExtensions: true
define root view entity ZC_Travel
provider contract transactional_query
as projection on ZI_Travel
{
key TravelUUID,
TravelId,
AgencyId,
CustomerId,
BeginDate,
EndDate,
TotalPrice,
CurrencyCode,
Description,
OverallStatus,
CreatedBy,
CreatedAt,
LastChangedBy,
LastChangedAt,
LocalLastChangedAt,
_Booking : redirected to composition child ZC_Booking
}

Definicion de Draft Table

Para cada entidad con soporte Draft necesita una tabla Draft separada. Esta tabla almacena las copias de trabajo temporales y debe tener la misma estructura que la tabla principal, complementada con campos de administracion especificos de Draft:

@EndUserText.label : 'Travel Draft'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
define table zdraft_travel {
key client : abap.clnt not null;
key travel_uuid : sysuuid_x16 not null; // Draft-UUID
travel_id : abap.numc(8);
agency_id : abap.numc(6);
customer_id : abap.numc(6);
begin_date : abap.dats;
end_date : abap.dats;
total_price : abap.curr(16,2);
currency_code : abap.cuky;
description : abap.string(256);
status : abap.char(1);
// Draft-spezifische Felder (automatisch vom Framework genutzt)
"%admin" : include sych_bdl_draft_admin_inc;
}

Draft-Admin Include

El Include sych_bdl_draft_admin_inc contiene campos de administracion importantes:

CampoDescripcion
draftentityuuidID Draft unico
draftentitycreationdatetimeMomento de creacion
draftentitylastchangedatetimeUltimo cambio
draftentitycreatedbyCreado por
draftentitylastchangedbyCambiado por
draftentityownershipstatePropiedad del Draft
hasactiveentityTiene version activa
isactiveentityEs version activa

Draft Actions

RAP proporciona Draft Actions automaticamente:

Edit Action

Inicia el modo de edicion y crea un Draft:

" In der Behavior Definition
draft action Edit;
" EML-Aufruf
MODIFY ENTITIES OF zi_travel
ENTITY Travel
EXECUTE Edit FROM VALUE #( ( TravelId = '00000001' ) )
MAPPED DATA(mapped)
FAILED DATA(failed)
REPORTED DATA(reported).

Activate Action

Activa el Draft y escribe los cambios en la base de datos:

" In der Behavior Definition
draft action Activate optimized;
" EML-Aufruf
MODIFY ENTITIES OF zi_travel
ENTITY Travel
EXECUTE Activate FROM VALUE #( ( %key-TravelId = '00000001' ) )
MAPPED mapped
FAILED failed
REPORTED reported.
COMMIT ENTITIES.

El sufijo optimized asegura que solo se escriban los campos modificados.

Discard Action

Descarta el Draft sin guardar:

" In der Behavior Definition
draft action Discard;
" EML-Aufruf
MODIFY ENTITIES OF zi_travel
ENTITY Travel
EXECUTE Discard FROM VALUE #( ( %key-TravelId = '00000001' ) )
FAILED failed
REPORTED reported.

Resume Action

Continua la edicion de un Draft existente:

" In der Behavior Definition
draft action Resume;
" EML-Aufruf
MODIFY ENTITIES OF zi_travel
ENTITY Travel
EXECUTE Resume FROM VALUE #( ( %key-TravelId = '00000001' ) )
RESULT DATA(result)
FAILED failed
REPORTED reported.

Prepare Action

Ejecuta validaciones sin activar:

" In der Behavior Definition
draft determine action Prepare {
validation validateDates;
validation validateCustomer;
}
" EML-Aufruf - prüft alle Draft-Validierungen
MODIFY ENTITIES OF zi_travel
ENTITY Travel
EXECUTE Prepare FROM VALUE #( ( %key-TravelId = '00000001' ) )
FAILED failed
REPORTED reported.

Ejemplo Completo de Draft

1. Behavior Definition

managed implementation in class zbp_i_travel unique;
strict ( 2 );
with draft;
define behavior for ZI_Travel alias Travel
persistent table ztravel
draft table zdraft_travel
lock master total etag LastChangedAt
authorization master ( instance )
etag master LastChangedAt
{
// Standard-Operationen
create;
update;
delete;
// Feldmapping
field ( readonly ) TravelId;
field ( readonly ) CreatedBy, CreatedAt, LastChangedBy, LastChangedAt;
field ( numbering : managed ) TravelId;
// Actions
action ( features : instance ) acceptTravel result [1] $self;
action ( features : instance ) rejectTravel result [1] $self;
// Validations - werden bei Prepare/Activate ausgeführt
validation validateDates on save { field BeginDate, EndDate; }
validation validateCustomer on save { field CustomerId; }
// Determinations
determination setStatusNew on modify { create; }
// Draft Actions
draft action Edit;
draft action Activate optimized;
draft action Discard;
draft action Resume;
draft determine action Prepare {
validation validateDates;
validation validateCustomer;
}
}

2. Projection con Draft

projection;
strict ( 2 );
use draft;
define behavior for ZC_Travel alias Travel
{
use create;
use update;
use delete;
use action acceptTravel;
use action rejectTravel;
use action Edit;
use action Activate;
use action Discard;
use action Resume;
use action Prepare;
}

3. Implementar Draft-Validation

CLASS lhc_travel DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS validateDates FOR VALIDATE ON SAVE
IMPORTING keys FOR Travel~validateDates.
ENDCLASS.
CLASS lhc_travel IMPLEMENTATION.
METHOD validateDates.
" Draft-Daten lesen (nicht aktive Daten!)
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( BeginDate EndDate )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travel).
LOOP AT lt_travel INTO DATA(ls_travel).
" Draft-Validierung: Warnung statt Fehler möglich
IF ls_travel-EndDate < ls_travel-BeginDate.
APPEND VALUE #(
%tky = ls_travel-%tky
%element-EndDate = if_abap_behv=>mk-on
) TO failed-travel.
APPEND VALUE #(
%tky = ls_travel-%tky
%state_area = 'VALIDATE_DATES'
%element-EndDate = if_abap_behv=>mk-on
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'Enddatum muss nach Beginndatum liegen'
)
) TO reported-travel.
ENDIF.
ENDLOOP.
ENDMETHOD.
ENDCLASS.

Draft en Fiori Elements

Cuando Draft esta activado, Fiori Elements muestra automaticamente:

  • Auto-Save: Los cambios se guardan automaticamente
  • Draft Indicator: Indica que existen cambios sin guardar
  • Boton Discard: Descarta todos los cambios
  • Boton Save: Activa el Draft (ejecuta validaciones)

Concurrent Access y Locking en Detalle

El framework RAP gestiona Locks automaticamente para asegurar la consistencia de datos. En Draft Handling hay dos escenarios criticos:

Escenario 1: Dos usuarios editan la misma instancia

Con Exclusive Lock (Estandar):

  1. Usuario A inicia Edit -> Se crea Draft, se establece Lock
  2. Usuario B intenta Edit -> Mensaje de error “El objeto esta siendo editado por Usuario A”
  3. Usuario A activa o descarta -> Se libera Lock
  4. Usuario B ahora puede editar

Escenario 2: Draft-Timeout

Cuando un usuario crea un Draft y abandona la sesion:

  • El Draft permanece en la tabla Draft
  • Al acceder de nuevo puede continuar con Resume
  • Otros usuarios siguen bloqueados (con Exclusive Lock)

Para evitar Drafts huerfanos, puede configurar un Background-Job que elimine automaticamente Drafts antiguos:

" Beispiel: Drafts älter als 7 Tage löschen
DELETE FROM zdraft_travel
WHERE draftentitylastchangedatetime < @lv_cutoff_timestamp.

Mejores Practicas

  1. Draft solo cuando sea necesario - Para apps CRUD simples sin formularios complejos, Draft a menudo es innecesario y aumenta la complejidad
  2. Validaciones en Prepare - Permite retroalimentacion temprana sin activacion, mejora la experiencia del usuario
  3. Definir Draft Table correctamente - Usar siempre el Admin-Include sych_bdl_draft_admin_inc
  4. Optimized Activate - El sufijo optimized en Activate mejora el rendimiento, ya que solo se escriben los campos modificados
  5. Usar State Areas - Agrupe mensajes de validacion para mejor UX con %state_area
  6. Configurar Draft Timeout - Configure un Background-Job para eliminar automaticamente Drafts antiguos
  7. No olvidar Testing - Pruebe todos los escenarios Draft: Edit, Activate, Discard, Resume y Concurrent Access

Resumen

Draft Handling es una caracteristica potente del RESTful ABAP Programming Model que mejora significativamente la experiencia del usuario en escenarios complejos de captura de datos. Los puntos mas importantes:

  • Draft vs. Active: Los Drafts son copias de trabajo temporales que solo se convierten en datos persistentes en la activacion
  • Draft Table: Una tabla separada almacena las instancias Draft con el Admin-Include para campos de administracion
  • Draft Actions: Edit, Activate, Discard, Resume y Prepare permiten el workflow Draft completo
  • Locking: Exclusive Lock previene la edicion simultanea, Shared Lock permite escenarios colaborativos
  • Validaciones: Con Prepare se pueden ejecutar validaciones sin activar el Draft

Con el uso correcto de Draft Handling crea aplicaciones Fiori profesionales que ofrecen una experiencia de usuario optima incluso en escenarios de entrada complejos.

Temas Relacionados