RAP desde cero · Lección 4 de 6
Validaciones en RAP: failed, reported y mensajes en el campo correcto
Añade comportamiento a la biblioteca (crear, modificar, borrar) y valida los datos al guardar, con mensajes de error que Fiori muestra junto al campo.
Hasta ahora la app de la biblioteca solo consulta. En esta lección le damos comportamiento: crear, modificar y borrar libros. Y como no queremos libros con 0 páginas ni valoraciones de 9 estrellas, añadimos validaciones.
1. Behavior Definition de la entidad raíz
Clic derecho en ZR_LibBook → New Behavior Definition, tipo Managed. Ajusta el resultado para que quede así:
managed implementation in class zbp_r_libbook unique;
strict ( 2 );
define behavior for ZR_LibBook alias Book
persistent table zlib_book
lock master
authorization master ( instance )
etag master LocalLastChangedAt
{
create;
update;
delete;
field ( readonly, numbering : managed ) BookUuid;
field ( readonly ) LocalCreatedBy, LocalCreatedAt, LocalLastChangedBy,
LocalLastChangedAt, LastChangedAt;
field ( mandatory ) BookId, Title, AuthorId;
validation validatePages on save { create; field Pages; }
validation validateRating on save { create; field Rating; }
mapping for zlib_book corresponding
{
BookUuid = book_uuid;
BookId = book_id;
AuthorId = author_id;
CurrencyCode = currency_code;
LocalCreatedBy = local_created_by;
LocalCreatedAt = local_created_at;
LocalLastChangedBy = local_last_changed_by;
LocalLastChangedAt = local_last_changed_at;
LastChangedAt = last_changed_at;
}
}
Línea a línea, lo importante:
| Línea | Qué hace |
|---|---|
managed |
El framework se encarga de leer, guardar y bloquear; tú solo escribes la lógica de negocio |
strict ( 2 ) |
Activa las comprobaciones más estrictas de sintaxis y buenas prácticas |
persistent table zlib_book |
Dónde guarda los datos el framework |
lock master |
Bloqueo pesimista mientras alguien edita |
etag master LocalLastChangedAt |
Bloqueo optimista: si otro usuario modificó el libro mientras tanto, tu cambio se rechaza |
numbering : managed |
RAP genera el UUID al crear |
mapping … corresponding |
Relaciona campos CDS y columnas de la tabla. Los que se llaman igual (Title/title) no hace falta listarlos |
validation … on save { create; field Pages; } |
Se ejecuta al guardar, si el libro es nuevo o si cambió Pages |
Pon el cursor en zbp_r_libbook y usa el quick fix (Ctrl+1) para que ADT genere la clase de implementación con los métodos vacíos.
2. Behavior Definition de la proyección
La proyección decide qué operaciones del objeto de negocio ofrece esta app. Clic derecho en ZC_LibBook → New Behavior Definition:
projection;
strict ( 2 );
define behavior for ZC_LibBook alias Book
use etag
{
use create;
use update;
use delete;
}
Si quisieras una app que solo modifica, bastaría con quitar use create y use delete. El objeto de negocio sigue siendo el mismo.
3. Las validaciones
En la clase zbp_r_libbook, pestaña Local Types, el handler queda así:
CLASS lhc_book DEFINITION INHERITING FROM cl_abap_behavior_handler.
PRIVATE SECTION.
METHODS get_instance_authorizations FOR INSTANCE AUTHORIZATION
IMPORTING keys REQUEST requested_authorizations FOR Book RESULT result.
METHODS validatePages FOR VALIDATE ON SAVE
IMPORTING keys FOR Book~validatePages.
METHODS validateRating FOR VALIDATE ON SAVE
IMPORTING keys FOR Book~validateRating.
ENDCLASS.
CLASS lhc_book IMPLEMENTATION.
METHOD get_instance_authorizations.
" Sin restricciones por ahora: lo vemos en la lección de seguridad
ENDMETHOD.
METHOD validatePages.
READ ENTITIES OF ZR_LibBook IN LOCAL MODE
ENTITY Book
FIELDS ( Pages )
WITH CORRESPONDING #( keys )
RESULT DATA(books).
LOOP AT books INTO DATA(book).
" 1. Limpiar los mensajes anteriores de esta validación
APPEND VALUE #( %tky = book-%tky
%state_area = 'VALIDATE_PAGES' ) TO reported-book.
IF book-Pages <= 0.
" 2. Marcar la instancia como fallida: no se guardará
APPEND VALUE #( %tky = book-%tky ) TO failed-book.
" 3. Explicar por qué, y en qué campo
APPEND VALUE #( %tky = book-%tky
%state_area = 'VALIDATE_PAGES'
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'El número de páginas debe ser mayor que cero' )
%element-Pages = if_abap_behv=>mk-on ) TO reported-book.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD validateRating.
READ ENTITIES OF ZR_LibBook IN LOCAL MODE
ENTITY Book
FIELDS ( Rating )
WITH CORRESPONDING #( keys )
RESULT DATA(books).
LOOP AT books INTO DATA(book).
APPEND VALUE #( %tky = book-%tky
%state_area = 'VALIDATE_RATING' ) TO reported-book.
IF book-Rating > 5.
APPEND VALUE #( %tky = book-%tky ) TO failed-book.
APPEND VALUE #( %tky = book-%tky
%state_area = 'VALIDATE_RATING'
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = |La valoración va de 0 a 5; recibí { book-Rating }| )
%element-Rating = if_abap_behv=>mk-on ) TO reported-book.
ENDIF.
ENDLOOP.
ENDMETHOD.
ENDCLASS.
El patrón, paso a paso
READ ENTITIES … IN LOCAL MODE: una validación solo recibe las claves (keys) de los libros afectados, así que primero hay que leer los datos.IN LOCAL MODEse salta las comprobaciones de autorización y de feature control, porque la lectura la hace el propio objeto de negocio.WITH CORRESPONDING #( keys )es elCORRESPONDINGde la lección 1.%tky: la clave «transaccional» de la instancia. Úsala siempre para referirte a un libro enfailedyreported.failed: dice qué instancias fallaron. Si una validación deja algo aquí, el guardado completo se rechaza.reported: dice por qué. Lleva el mensaje (%msg) y el campo afectado (%element-Pages), que Fiori resalta en rojo.%state_area: agrupa los mensajes de una misma validación. Al empezar se añade una entrada vacía con esa área para borrar los mensajes de la ejecución anterior: así, cuando el usuario corrige el dato, el error desaparece. Cobra todo su sentido con el modo draft, pero conviene acostumbrarse desde el principio.
Regla práctica: cada
APPEND … TO failed-…va acompañado de unAPPEND … TO reported-…. Un fallo sin mensaje deja al usuario sin saber qué corregir; un mensaje sin fallo es solo un aviso y el guardado sigue adelante.
Mensajes con clase de mensajes
new_message_with_text es cómodo para aprender. En un proyecto real, los textos suelen ir en una clase de mensajes para poder traducirlos:
%msg = new_message( id = 'ZLIB_MESSAGES'
number = '001'
v1 = book-BookId
severity = if_abap_behv_message=>severity-error )
4. Pruébalo
Activa todo y vuelve a la vista previa del Service Binding (lección 3). Ahora aparecen los botones Create y Delete.
- Crea un libro con 0 páginas y pulsa Save: el guardado se rechaza y el campo Pages aparece en rojo con tu mensaje.
- Pon 350 páginas y una valoración de 9: ahora el error está en Rating.
- Corrige la valoración a 4 y guarda: el libro se crea y los mensajes desaparecen.
Resumen
- La Behavior Definition declara qué se puede hacer (
create,update,delete) y qué reglas se aplican (validation). - La proyección decide qué parte de ese comportamiento ofrece cada app.
- Una validación lee los datos, marca las instancias erróneas en
failedy explica el motivo enreported, en el campo correcto.
Con esto termina el bloque básico de la serie: tienes un objeto de negocio RAP completo, con datos, servicio, interfaz y reglas. El siguiente nivel entra en la lógica de negocio: numeración propia, determinaciones y acciones.
Recibe los nuevos tutoriales
Un correo cuando publique algo nuevo. Sin spam; te das de baja cuando quieras.
Te enviaré un correo para confirmar la suscripción. Datos tratados según la política de privacidad.