Introducción
Aplicación de técnicas y conceptos básicos
Trabajar con clases locales
Lectura de datos de la base de datos
Trabajar con objetos de datos estructurados
Trabajar con tablas internas complejas
Implementación de actualizaciones de base de datos mediante business objects
Descripción del modelo de programación de aplicaciones ABAP RESTful

Añadir lógica ABAP

Objective

After completing this lesson, you will be able to implementar el comportamiento de un business object.

Validaciones

Verificación de la clave semántica

En el modelo de programación de aplicaciones ABAP RESTful, la clave de una tabla de base de datos a menudo se compone del campo de cliente y un campo UUID, cuyo valor se asigna automáticamente por el tiempo de ejecución cuando crea una nueva instancia del business object. Esta combinación de campos es suficiente para garantizar que el sistema pueda identificar cada registro en la tabla de forma unívoca. Sin embargo, además de esta clave técnica, nuestro objeto también tiene una clave semántica, en este caso la combinación de compañía aérea y número de vuelo, que también debe ser unívoca según la lógica empresarial. Para garantizar la univocidad de esta combinación de campos, debe implementar su propia verificación en forma de validación.

Las validaciones se declaran en la definición de comportamiento de la entidad de vista CDS y se implementan en la clase de implementación de comportamiento.

Verificaciones de entrada en la aplicación

Además de verificar la clave semántica, hay otras verificaciones que debe realizar. Por ejemplo, aunque la aplicación generada le permite crear, leer, actualizar y borrar datos, aún no contiene verificaciones de consistencia. En consecuencia, puede crear conexiones de vuelos para compañías aéreas que no existen o en las que los aeropuertos de salida y de destino son los mismos.

Para evitar que esto ocurra, defina otras validaciones en la definición de comportamiento e impleméntelas en la clase de implementación de comportamiento.

Creación de textos de mensaje

Antes de crear la validación, debe crear los textos que desea visualizar. Esto se realiza mediante una clase de mensaje. Una clase de mensaje es una colección de hasta 1000 mensajes que pertenecen a un área de aplicación determinada. Como se muestra en la figura, cada texto tiene un número que identifica el mensaje de forma unívoca dentro de la clase de mensaje.

Para crear una nueva clase de mensaje, proceda de la siguiente manera:

  1. Seleccione FicheroNuevoOtro… y escriba mensaje en el campo de filtro.

  2. Haga doble clic en la entrada Clase de mensaje en la lista de aciertos y, a continuación, introduzca un paquete, un nombre y una descripción para la nueva clase de mensaje. Seleccione Siguiente.

  3. Asigne la clase de mensaje a una orden de transporte y seleccione Finalizar.

Los mensajes también pueden contener reserva-espacios, que se sustituyen por valores concretos cuando se visualiza el mensaje. Los marcadores de posición se indican con el signo & seguido de un número. Puede utilizar hasta cuatro marcadores de posición en cada mensaje.

Definición de la validación

Para definir una validación, añada una declaración de validación a la definición de comportamiento de su business object. En este ejemplo, la validación debe realizarse cada vez que el usuario guarda un registro de datos, y podría ser cuando crea el registro o si lo modifica posteriormente.

Cuando define la validación en la definición de comportamiento, un mensaje de advertencia le indica que el método correspondiente no existe. Utilice una corrección rápida (combinación de teclas CTRL + 1) para añadir el método a la implementación de comportamiento. La implementación de comportamiento es una clase local dentro de su pool de comportamientos. La definición del método contiene el suplemento FOR VALIDATE ON SAVE, que lo identifica como la implementación de la validación. Tiene un parámetro de importación KEYS. Se trata de una tabla interna que contiene las claves de los objetos creados o modificados. Se utilizan para leer los datos reales que el usuario ha introducido.

El suplemento FOR Connection~CheckSemanticKey enlaza el método con la validación CheckSemanticKey de la definición de comportamiento. Aquí, Conexión es el nombre alias de la entidad de vista Z_R_CONNECTION.

Al definir una validación, también debe crear su implementación. Este es un método en el pool de comportamiento. La forma más fácil de hacerlo es utilizar una solución rápida. Sitúe el cursor en el nombre de la validación y pulse CTRL + 1. ADT propone crear el método. Haga doble clic en la propuesta para crear el método.

El proceso de validación

Nota

Algunos ejemplos de código de esta sección utilizan sentencias SELECT dentro de bucles. Esto se ha hecho para mantener los ejemplos simples. Tenga en cuenta que las SELECT en loops pueden causar problemas de rendimiento y deben evitarse.

Cuando el sistema desencadena una validación, llama la implementación correspondiente. El parámetro de importación KEYS contiene las claves de los registros de datos modificados. Utilice las claves para leer los campos de los registros que necesita mediante Entity Manipulation Language (EML). EML es un conjunto especial de sentencias en ABAP que le permite abordar business objects.

Una vez leídos los datos, puede realizar las verificaciones que necesite. Si la verificación falla, deberá emitir un mensaje de error adecuado y, lo que es más importante, decirle al framework que no escriba las modificaciones en la base de datos.

La primera tarea en una validación es leer la entrada de usuario. Para ello, utilice la sentencia Entity Manipulation Language (EML) READ ENTITIES. Las claves de los registros de datos correspondientes se transfieren a la validación mediante las claves de parámetro de importación.

Los campos que necesita para validar la clave semántica son CarrierID para la compañía aérea y ConnectionID para el número de vuelo.

El fragmento de código utiliza la palabra clave CORRESPONDING y una declaración en línea para el conjunto de resultados. A continuación, puede ver el código equivalente utilizando variables definidas explícitamente, lo que facilita la comprensión de los tipos que se utilizan.

Code Snippet
12345678910111213
DATA read_keys TYPE TABLE FOR READ IMPORT zs4d400_r_connection. DATA connections TYPE TABLE FOR READ RESULT zs4d400_r_connection. read_keys = CORRESPONDING #( keys ). READ ENTITIES OF zs4d400_r_connection IN LOCAL MODE ENTITY Connection FIELDS ( CarrierID ConnectionID ) WITH read_keys RESULT connections.

Una vez leída la entrada de usuario, puede utilizar los valores de CarrierID y ConnectionID para ver si esta clave semántica ya se ha utilizado en otro conjunto de datos distinto al que está procesando. Dado que la combinación de claves podría estar en la tabla activa o en la tabla borrador, debe buscar en ambas y la forma más eficiente de hacerlo es con una unión.

El conjunto de resultados de esta consulta siempre debe estar vacío. De lo contrario, hay más registros con la misma combinación de CarrierID y ConnectionID, lo que significa que el registro que el usuario está intentando crear actualmente es un duplicado y debe rechazarse.

Si la combinación de ID de transportista e ID de conexión ya existe, habrá una entrada en la tabla check_result. En este caso, debe emitir un mensaje.

El primer paso es crear un objeto de mensaje. Para ello, utilice la autoreferencia y llame al método new_message( ). El ID, el número y la gravedad de los parámetros son obligatorios. ID es el nombre de la clase de mensaje que contiene el mensaje; el número es el número de mensaje. La gravedad clasifica el mensaje como mensaje de éxito, información, advertencia o error. La clase de implementación de comportamiento contiene una constante estructurada ms cuyos componentes representan los diferentes niveles de gravedad. En este caso, necesita el nivel de gravedad ms-error.

El método también tiene parámetros de importación opcionales v1, v2, v3 y v4. Se utilizan para sustituir marcadores de posición por valores concretos. En este ejemplo, el marcador de posición &1 se sustituye por el código de aerolínea, el marcador de posición &2 se sustituye por el número de vuelo.

El resultado de la llamada de método es una referencia de objeto. En el siguiente paso, pasará el objeto al tiempo de ejecución para que el mensaje de error se devuelva al servicio OData y se visualice en la vista previa de la aplicación.

Para que el tiempo de ejecución muestre un mensaje, debe notificarlo mediante la estructura notificada. Este es un parámetro changing implícito de todos los métodos de validación y es una estructura profunda. Contiene un componente con el nombre alias de la entidad. Este componente es una tabla interna.

Para notificar el mensaje, debe hacer tres cosas:

  1. Añada la clave del registro afectado a la tabla interna. Puede hacerlo utilizando el grupo de campos %tky. Cuando agrupa campos como este, puede direccionar el nombre del grupo en lugar de tener que dirigirse a cada campo individualmente.
  2. Adjunte el objeto de mensaje a la tabla. Para ello, asigne la referencia de objeto del objeto de mensaje al componente %msg de la tabla interna.
  3. Vincule el mensaje al campo afectado. Esto garantiza que el campo se resalte en la aplicación. Esto, a su vez, ayuda al usuario a navegar mejor por la aplicación. Para ello, utilice el componente %element de la tabla interna.

En este ejemplo, reported_record es una estructura con el tipo de línea de la tabla interna reported-connection. Rellene el componente %tky con el contenido del grupo de campos %tky en la conexión de estructura. Esta estructura de conexión se utiliza como área de trabajo para la tabla interna que contiene los datos introducidos por el usuario. A continuación, asigne el objeto de mensaje que ha creado utilizando el método new_message( ) al componente %msg. Finalmente, para vincular el mensaje a los campos CarrierID y ConnectionID, utilice la estructura %element. %element contiene un componente para cada campo de la entidad. Si fija un componente en verdadero, el campo de entrada correspondiente se resaltará en la aplicación. Para ello, utilice la constante estructurada if_abap_behv=>mk. Este tiene el componente activado para marcado/verdadero y desactivado para no marcado/falso.

No puede utilizar las constantes globales abap_true y abap_false en este punto, ya que sus tipos de datos no son compatibles.

Además de emitir el mensaje, también debe indicar al tiempo de ejecución que no guarde los datos incorrectos. Para ello, utilice la estructura fallida del método de validación. Fallido es un parámetro changing implícito que está presente en todos los métodos de validación.

Para notificar un registro como fallido, agregue su grupo de campos %tky al grupo de campos %tky de la tabla interna. Fallo de conexión.

La siguiente validación verifica que la compañía aérea que ha introducido el usuario exista realmente. El primer paso es leer la entrada de usuario utilizando la sentencia EML READ ENTITIES. Esta vez, solo necesita leer el campo CarrierID.

La sentencia SELECT SINGLE lee los datos mediante la entidad de vista CDS /dmo/i_carrier y verifica si existe la compañía aérea indicada. Si es así, el valor de la constante global abap_true ("X") se coloca en el campo. Si existe es inicial siguiendo la sentencia SELECT, debe emitir un mensaje, notificarlo y añadir el registro a la estructura fallida como lo hizo en el ejemplo anterior.

La validación final comprueba que los aeropuertos de origen y destino son diferentes. El primer paso es leer la entrada de usuario mediante una sentencia READ ENTITIES. Esta vez, los campos AirportFromID y AirportToID son relevantes.

Si los aeropuertos de salida y llegada son los mismos, debe emitir el mensaje correspondiente y rellenar las estructuras notificadas y fallidas. El extracto de código muestra la codificación relevante para crear el mensaje. La codificación para rellenar las estructuras notificadas y fallidas es la misma que en los ejemplos anteriores.

Cómo validar la clave semántica

Determinaciones

Determinar ciudades según códigos de aeropuerto

En la aplicación de ejemplo, la entidad de conexión de vuelos contiene un aeropuerto de salida, una ciudad y un país, y un aeropuerto de llegada, una ciudad y un país. Si bien sería posible obligar al usuario a introducir toda esta información, es mejor en términos de experiencia de usuario y consistencia de datos que el usuario introduzca solo los códigos de aeropuerto y que la aplicación lea la información de ciudad y país correspondiente de la base de datos. En el modelo de programación de aplicaciones ABAP RESTful, puede realizar este tipo de tarea utilizando una determinación.

Primero implementará la determinación. A continuación, aprenderá a desactivar la entrada para los campos que se rellenarán automáticamente.

Definición de la determinación

Defina una determinación en la definición de comportamiento de un business object. La determinación aquí se llama getCities, se llamará siempre que se guarde el business object y se haya modificado al menos uno de los campos AirportFromID y AirportToID. Puede utilizar una corrección rápida en la definición de comportamiento para crear el método correspondiente en la implementación de comportamiento.

El proceso de determinación

Exploremos cada paso del proceso de determinación.

Cuando el sistema desencadena una determinación, llama la implementación correspondiente. El parámetro de importación KEYS contiene las claves de los registros de datos modificados. En el método de determinación, utilice EML para leer los datos basados en las claves exactamente de la misma manera que lo hizo en las validaciones. Sin embargo, en una determinación, también manipula los datos en el método y, por lo tanto, debe actualizar los datos que tiene el framework mediante la sentencia EML UPDATE.

Nota

Algunos ejemplos de código de esta sección utilizan sentencias SELECT dentro de bucles. Esto se ha hecho para mantener los ejemplos simples. Tenga en cuenta que las SELECT en loops pueden causar problemas de rendimiento y deben evitarse.

Al principio de la determinación se lee la entrada de usuario mediante EML. Necesita los campos AirportFromID y AirportToID y los utilizará para completar la información de ciudad y país.

El modelo de datos de demostración proporciona una entidad de vista CDS /dmo/i_airport que puede utilizar para leer la ciudad y el país en los que se encuentra un aeropuerto en particular. El ejemplo utiliza la variante de la cláusula INTO en la que especifica explícitamente los campos de la estructura que desea rellenar. Recuerde que las modificaciones de los datos se encuentran en el área de trabajo de la tabla interna y que debe devolverlas a la propia tabla mediante la sentencia MODIFY.

La sentencia READ ENTITIES devuelve una tabla interna con el tipo derivado FOR READ RESULT. Para modificar los datos en la memoria intermedia transaccional, necesita una sentencia MODIFY ENTITIES. Transfiera los datos que desea modificar a esta sentencia utilizando una tabla interna con el tipo derivado FOR UPDATE. Los campos de datos son idénticos en ambos tipos, sin embargo, la tabla FOR UPDATE tiene una estructura adicional llamada %control que contiene información administrativa.

No puede pasar la tabla de conexiones a la sentencia MODIFY ENTITIES. Por lo tanto, debe copiar sus datos en una tabla interna de tipo adecuado (connections_upd) antes de realizar la modificación real.

Para actualizar los datos con los campos que ha rellenado en la determinación, utilice la sentencia MODIFY ENTITIES. En ella, especifique qué campos deben actualizarse en la cláusula FIELDS y transfiera los datos en una tabla interna utilizando el suplemento WITH. Esta tabla debe tener el tipo de datos derivado correcto, que en este caso sería TYPE TABLE FOR UPDATE zsd4d400_r_connection.

La sentencia MODIFY ENTITIES puede devolver mensajes, que recibe mediante la cláusula REPORTED. A continuación, propague estos mensajes a su propio business object copiando el contenido de la tabla interna en la estructura REPORTED del método de determinación.

Cómo determinar las ciudades y los países

Validar el precio del vuelo

En este ejercicio, defina e implemente una validación para el precio del vuelo.

Modelo:

  • ninguno

Solución:

  • /LRN/S4D400_R_FLIGHT (Definición de comportamiento)
  • /LRN/BP_S4D400_R_FLIGHT (clase global)

Prerrequisitos

Ha completado los ejercicios anteriores. Ha creado y rellenado la tabla de base de datos Z##FLIGHT (donde ## es su número de grupo) y ha generado los objetos de desarrollo para un servicio de IU OData.

Tarea 1: Validar el precio

Defina e implemente una validación para verificar que el campo Precio tenga un valor positivo (nombre sugerido: validatePrice). Si el valor es negativo o igual a cero, rechace la modificación y notifique un mensaje de error adecuado de la clase de mensaje /LRN/S4D400.

Pasos

  1. En la definición de comportamiento ZR_##FLIGHT, defina una nueva validación validatePrice. Asegúrese de que la validación siempre se ejecute durante la creación de la operación estándar, pero solo si el valor del Precio se ha modificado para todas las demás operaciones.

    Consejo

    Utilice la finalización de código siempre que sea posible para introducir el código.
    1. Abra la definición de comportamiento ZR_##FLIGHT.

    2. Ajuste el código de la siguiente manera:

      Code Snippet
      12345
      create; update; delete; validation validatePrice on save { create; field Price; }
  2. Active la definición de comportamiento.

    1. Pulse Ctrl + F3 para activar la definición de comportamiento.

  3. Utilice una corrección rápida para crear el método de implementación de validación en la clase de programa de control de comportamiento.

    1. Sitúe el cursor en el nombre de la validación y seleccione Ctrl + 1.

    2. Haga doble clic en la entrada Añadir método para validación....

  4. Al principio del método validatePrice, declare un objeto de datos estructurado que escriba con el tipo de línea de failed-flight (nombre sugerido: failed_record). De forma similar, declare un objeto de datos estructurado que escriba con el tipo de línea de vuelo notificado (nombre sugerido: reported_record).

    Nota

    Estas estructuras se utilizarán para añadir filas a vuelo fallido y vuelo notificado, en caso de que la validación encuentre un error.
    1. Añada el código siguiente:

      Code Snippet
      12
      DATA failed_record LIKE LINE OF failed-flight. DATA reported_record LIKE LINE OF reported-flight.
  5. Utilice una sentencia READ ENTITIES para leer la entrada de usuario desde la memoria intermedia transaccional. Utilice el suplemento IN LOCAL MODE y asegúrese de que solo se leen los campos clave y el campo Precio. Utilice una declaración en línea para el conjunto de resultados (nombre sugerido: vuelos).

    Nota

    No es necesario enumerar los campos clave después del suplemento FIELDS. READ ENTITIES siempre lee los campos clave.
    1. Después de las declaraciones, añada el siguiente código, sustituyendo ## por su número de grupo:

      Code Snippet
      12345
      READ ENTITIES OF ZR_##Flight IN LOCAL MODE ENTITY Flight FIELDS ( Price ) WITH CORRESPONDING #( keys ) RESULT DATA(flights).
  6. Implemente un loop sobre los datos que acaba de leer. Utilice una declaración en línea para el área de trabajo (nombre sugerido: vuelo).

    1. Después de la sentencia EML, añada el siguiente código:

      Code Snippet
      123
      LOOP AT flights INTO DATA(flight). ENDLOOP.
  7. En el bucle, verifique si el componente Precio es mayor que cero. Si no es así, rellene la estructura failed_record con la clave del vuelo actual y añádala como nueva fila a la tabla failed-flight. De forma similar, rellene la estructura reported_record con la clave del vuelo actual y añádala como nueva fila a la tabla reported-flight.

    Consejo

    En los business objects habilitados para borradores, se recomienda utilizar el componente %tky para asignar la clave.
    1. Dentro del bucle, añada el siguiente código:

      Code Snippet
      12345678
      IF flight-price <= 0. failed_record-%tky = flight-%tky. APPEND failed_record TO failed-flight. reported_record-%tky = flight-%tky. APPEND reported_record TO reported-flight. ENDIF.
  8. Antes de la sentencia APPEND, complete el componente %msg de la estructura reported_record con una referencia a un objeto de mensaje. Para crear el objeto de mensaje, llame el método new_message con la siguiente entrada:

    Nombre de parámetroValor
    ID"/LRN/S4D400"
    number"101"
    gravedadms-error
    1. Ajuste el código de la siguiente manera:

      Code Snippet
      123456789101112131415
      LOOP AT flights INTO DATA(flight). IF flight-price <= 0. failed_record-%tky = flight-%tky. APPEND failed_record TO failed-flight. reported_record-%tky = flight-%tky. reported_record-%msg = new_message( id = '/LRN/S4D400' number = '101' severity = ms-error ). APPEND reported_record TO reported-flight. ENDIF. ENDLOOP.
  9. Active la clase.

    1. Pulse Ctrl + F3 para activar la clase.

Tarea 2: Probar y depurar

Fije un breakpoint en la implementación de validación. Reinicie la vista previa del servicio IU OData y modifique el precio de un vuelo existente. Realice entradas válidas y no válidas y depure la validación.

Pasos

  1. Fije un breakpoint en la sentencia READ ENTITIES del método validatePrice.

    1. En la implementación del método validatePrice, busque la sentencia READ ENTITIES y haga doble clic en el área a la izquierda del número de fila para fijar un breakpoint.

  2. Reinicie la vista previa del servicio IU OData.

    1. Cierre la ventana del navegador o la pestaña del navegador que contiene la vista previa.

    2. Abra la vinculación de servicio ZUI_##FLIGHT_O4. En la lista Conjunto de entidades y asociación de la derecha, seleccione primero la entrada Vuelo y, a continuación, Vista previa....

  3. En la aplicación, visualice la lista de vuelos, abra los detalles de uno de los vuelos y cambie al modo de modificación.

    1. Continúe como lo ha hecho en los ejercicios anteriores.

  4. Realice algunas modificaciones en el precio y, a continuación, seleccione Guardar. Analice la validación en el depurador.

    1. Continúe como lo ha hecho en los ejercicios anteriores.