Guia de introdução
Aplicação de técnicas básicas e conceitos
Trabalhar com classes locais
Ler dados do banco de dados
Trabalhar com objetos de dados estruturados
Trabalhar com tabelas internas complexas
Implementar atualizações do banco de dados utilizando business objects
Descrição do modelo de programação de aplicativos ABAP RESTful

Adicionar lógica ABAP

Objective

After completing this lesson, you will be able to implementar o comportamento de um business object.

Validações

Verificação da chave semântica

No modelo de programação de aplicação ABAP RESTful, a chave de uma tabela de banco de dados é frequentemente composta pelo campo de mandante e um campo UUID, cujo valor é atribuído automaticamente pelo tempo de execução quando você cria uma nova instância do business object. Esta combinação de campos é suficiente para garantir que o sistema possa identificar cada registro na tabela de forma única. No entanto, assim como esta chave técnica, o nosso objeto também tem uma chave semântica - neste caso, a combinação de companhia aérea e número do voo, que também deve ser única de acordo com a lógica empresarial. Para garantir a univocidade desta combinação de campos, você deve implementar sua própria verificação na forma de uma validação.

Você declara validações na definição de comportamento da entidade da visão CDS e implementa as mesmas na classe de implementação de comportamento.

Verificações de entrada no app

Além de verificar a chave semântica, existem outras verificações que você precisa executar. Por exemplo, embora o app gerado permita que você crie, leia, atualize e exclua dados, ele ainda não contém verificações de consistência. Consequentemente, você pode criar conexões de voo para companhias aéreas que não existem ou onde os aeroportos de partida e de destino são os mesmos.

Para evitar que isso aconteça, você define outras validações na definição de comportamento e implementa as mesmas na classe de implementação de comportamento.

Criar textos de mensagem

Antes de criar a validação, você deve criar os textos que quer exibir. Você efetua isso utilizando uma classe de mensagens. Uma classe de mensagens é uma coleção de até 1000 mensagens que pertencem a uma determinada área de aplicação. Como mostrado na figura, cada texto tem um número que identifica a mensagem de forma única dentro da classe de mensagens.

Para criar uma nova classe de mensagens, proceda da seguinte forma:

  1. Selecione ArquivoNovoOutro… e digite mensagem no campo de filtro.

  2. Clique duas vezes na entrada Classe de mensagens na lista de ocorrências e, em seguida, insira um pacote, nome e descrição para a nova classe de mensagens. Selecione Avançar.

  3. Atribua a classe de mensagem a uma ordem de transporte e selecione Concluir.

As mensagens também podem conter caracteres de preenchimento, que são substituídos por valores concretos quando a mensagem é exibida. Os caracteres de preenchimento são indicados pelo símbolo de E comercial seguido por um número. Você pode utilizar até quatro caracteres de preenchimento em cada mensagem.

Definição da validação

Para definir uma validação, você adiciona uma declaração de validação à definição de comportamento do seu business object. Neste exemplo, a validação deve ser executada sempre que o usuário gravar um registro de dados e isso pode ser quando cria o registro ou se ele o modifica posteriormente.

Quando você define a validação na definição de comportamento, um aviso informa que o método correspondente não existe. Utilize uma solução rápida (combinação de teclas CTRL + 1) para adicionar o método à implementação de comportamento. A implementação de comportamento é uma classe local dentro do seu pool de comportamentos. A definição de método contém o suplemento FOR VALIDATE ON SAVE, que o identifica como a implementação da validação. Ele tem um parâmetro de importação KEYS. Esta é uma tabela interna que contém as chaves dos objetos criados ou modificados. Você os utiliza para ler os dados reais que o usuário inseriu.

O suplemento FOR Connection~CheckSemanticKey liga o método à validação CheckSemanticKey da definição de comportamento. Aqui, Conexão é o nome do alias da entidade de visão Z_R_CONNECTION.

Quando você define uma validação, também deve criar a respectiva implementação. Este é um método no pool de comportamento. A maneira mais fácil de fazer isso é usar uma solução rápida. Posicione o cursor no nome da validação e pressione CTRL + 1. A ADT propõe a criação do método. Clique duas vezes na proposta para criar o método.

O processo de validação

Nota

Alguns exemplos de código nesta seção usam instruções SELECT dentro de loops. Isso foi feito para manter os exemplos simples. Considere que SELECTs em loops podem causar problemas de performance e devem ser evitadas.

Quando o sistema aciona uma validação, ele chama a implementação correspondente. O parâmetro de importação KEYS contém as chaves dos registros de dados que foram modificados. Você utiliza as chaves para ler os campos dos registros necessários utilizando Entity Manipulation Language (EML). EML é um conjunto especial de instruções no ABAP que permite que você aborde business objects.

Depois de ler os dados, você pode executar as verificações necessárias. Se a verificação falhar, você precisará emitir uma mensagem de erro adequada e, o mais importante, dizer ao framework para não escrever as modificações no banco de dados.

A primeira tarefa em uma validação é ler a entrada do usuário. Você efetua isso utilizando a instrução Entity Manipulation Language (EML) READ ENTITIES. As chaves dos registros de dados correspondentes são transferidas para a validação usando as chaves de parâmetro de importação.

Os campos necessários para validar a chave semântica são CarrierID para a companhia aérea e ConnectionID para o número do voo.

O snippet de código utiliza a palavra-chave CORRESPONDING e uma declaração inline para o conjunto de resultados. Abaixo, você vê o código equivalente usando variáveis definidas explicitamente, o que facilita a compreensão dos tipos utilizados.

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.

Depois de ler a entrada do usuário, você pode usar os valores de CarrierID e ConnectionID para ver se essa chave semântica já foi usada em outro conjunto de dados diferente daquele que você está processando agora. Uma vez que a combinação de chaves pode estar na tabela ativa ou na tabela de esboço, você precisa procurar as duas e a forma mais eficiente de efetuar isso é com uma união.

O conjunto de resultados desta consulta deve estar sempre vazio. Caso contrário, existem mais registros com a mesma combinação de CarrierID e ConnectionID, isso significa que o registro que o usuário está tentando criar é um duplicado e deve ser rejeitado.

Se a combinação de ID de agente de frete e ID de conexão já existir, existirá uma entrada na tabela check_result. Neste caso, você deve emitir uma mensagem.

A primeira etapa é criar um objeto de mensagem. Você faz isso usando a autorreferência e chamando o método new_message( ). Os parâmetros ID, número e gravidade são obrigatórios. O ID é o nome da classe de mensagens que contém a mensagem; o número é o número da mensagem. A gravidade classifica a mensagem como mensagem de êxito, informação, advertência ou erro. A classe de implementação de comportamento contém uma constante estruturada ms cujos componentes representam os diferentes níveis de gravidade. Neste caso, você precisa do nível de gravidade ms-error.

O método também tem parâmetros de importação opcionais v1, v2, v3 e v4. Você usa estes caracteres de preenchimento para substituir caracteres de preenchimento por valores concretos. Neste exemplo, o caractere de preenchimento &1 é substituído pelo código da companhia aérea, o caractere de preenchimento &2 é substituído pelo número do voo.

O resultado da chamada de método é uma referência a objetos. Na etapa seguinte, você transferirá o objeto para o tempo de execução para que a mensagem de erro retorne ao serviço OData e seja exibida na visualização do app.

Para que o tempo de execução exiba uma mensagem, você deve notificá-la utilizando a estrutura reportada. Este é um parâmetro de modificação implícito de todos os métodos de validação e é uma estrutura profunda. Ele contém um componente com o nome do alias da entidade. Este componente é uma tabela interna.

Para notificar a mensagem, você deve efetuar três coisas:

  1. Adicione a chave do registro afetado à tabela interna. Você pode efetuar isso utilizando o grupo de campos %tky. Quando você agrupa campos como este, pode abordar o nome do grupo em vez de ter que abordar cada campo individualmente.
  2. Anexe o objeto de mensagem à tabela. Você efetua isso atribuindo a referência a objetos do objeto de mensagem ao componente %msg da tabela interna.
  3. Ligue a mensagem ao campo afetado. Isso garante que o campo é destacado no app. Isso, por sua vez, ajuda o usuário a navegar melhor no app. Você efetua isso utilizando o componente %element da tabela interna.

Neste exemplo, reported_record é uma estrutura com o tipo de linha da tabela interna reported-connection. Você preenche o componente %tky com o conteúdo do grupo de campos %tky na conexão de estrutura. Esta estrutura de conexão é utilizada como área de trabalho para a tabela interna que contém os dados que o usuário inseriu. Em seguida, você atribui o objeto de mensagem que criou usando o método new_message( ) ao componente %msg. Por fim, para ligar a mensagem aos campos CarrierID e ConnectionID, você utiliza a estrutura %element. %element contém um componente para cada campo na entidade. Se você definir um componente como verdadeiro, o campo de entrada correspondente será destacado no app. Você efetua isso utilizando a constante estruturada if_abap_behv=>mk. Este tem o componente ativado para marcado/verdadeiro e desativado para desmarcado/falso.

Você não pode utilizar as constantes globais abap_true e abap_false neste momento, uma vez que os respectivos tipos de dados não são compatíveis.

Além de emitir a mensagem, você também deve informar o tempo de execução para não salvar os dados incorretos. Para isso, você usa a estrutura falhada do método de validação. Falhado é um parâmetro de modificação implícito que está presente em todos os métodos de validação.

Para reportar um registro como falhado, adicione seu grupo de campos %tky ao grupo de campos %tky da tabela interna com falha de conexão.

A próxima validação verifica se a companhia aérea que o usuário inseriu existe realmente. A primeira etapa é ler a entrada do usuário usando a instrução EML READ ENTITIES. Desta vez, você só precisa ler o campo CarrierID.

A instrução SELECT SINGLE lê dados utilizando a entidade de visão CDS /dmo/i_carrier e verifica se a companhia aérea indicada existe. Em caso afirmativo, o valor da constante global abap_true ('X') é colocado no campo. Se existir for inicial seguindo a instrução SELECT, você deve emitir uma mensagem, notificá-la e adicionar o registro à estrutura falhada como fez no exemplo anterior.

A validação final verifica se os aeroportos de origem e de destino são diferentes. A primeira etapa é ler a entrada do usuário usando uma instrução READ ENTITIES. Desta vez, os campos AirportFromID e AirportToID são relevantes.

Se os aeroportos de partida e de chegada forem os mesmos, você deve emitir a mensagem correspondente e preencher as estruturas reportadas e falhadas. O extrato do código exibe a codificação relevante para criar a mensagem. A codificação para preencher as estruturas reportadas e falhadas é a mesma que nos exemplos anteriores.

Como validar a chave semântica

Determinações

Determinar cidades com base em códigos de aeroporto

No app de exemplo, a entidade de conexão de voo contém um aeroporto, cidade e país de partida e um aeroporto, cidade e país de chegada. Embora seja possível forçar o usuário a inserir todas essas informações, é melhor em termos de experiência do usuário e consistência de dados fazer com que ele insira apenas os códigos de aeroporto e para que o app leia as informações de cidade e país correspondentes do banco de dados. No modelo de programação de aplicação ABAP RESTful, você pode executar este tipo de tarefa utilizando uma determinação.

Primeiro, você implementará a determinação. Em seguida, você aprenderá como desativar a entrada para os campos que serão preenchidos automaticamente.

Definição da determinação

Você define uma determinação na definição de comportamento de um business object. A determinação aqui é chamada de getCities, ela será chamada sempre que o business object for salvo e pelo menos um dos campos AirportFromID e AirportToID tiver sido modificado. Você pode utilizar uma solução rápida na definição de comportamento para criar o método correspondente na implementação de comportamento.

O processo de determinação

Vamos explorar cada etapa do processo de determinação.

Quando o sistema aciona uma determinação, ele chama a implementação correspondente. O parâmetro de importação KEYS contém as chaves dos registros de dados que foram modificados. No método de determinação, você usa EML para ler os dados com base nas chaves exatamente da mesma forma que você efetuou nas validações. No entanto, em uma determinação, você também manipula os dados no método e, consequentemente, deve atualizar os dados mantidos pelo framework usando a instrução EML UPDATE.

Nota

Alguns exemplos de código nesta seção usam instruções SELECT dentro de loops. Isso foi feito para manter os exemplos simples. Considere que SELECTs em loops podem causar problemas de performance e devem ser evitadas.

No início da determinação, você lê a entrada do usuário utilizando EML. Você precisa dos campos AirportFromID e AirportToID e os utilizará para preencher as informações de cidade e país.

O modelo de dados de demonstração fornece uma entidade de visão CDS /dmo/i_airport que você pode utilizar para ler a cidade e o país nos quais um determinado aeroporto está localizado. O exemplo usa a variante da cláusula INTO na qual você especifica explicitamente os campos da estrutura que deseja preencher. Lembre-se de que as modificações nos dados estão na área de trabalho da tabela interna e que você deve retorná-las à própria tabela usando a instrução MODIFY.

A instrução READ ENTITIES retorna uma tabela interna com o tipo derivado FOR READ RESULT. Para modificar os dados no buffer transacional, você precisa de uma instrução MODIFY ENTITIES. Você transfere os dados que quer modificar para esta instrução usando uma tabela interna com o tipo derivado FOR UPDATE. Os campos de dados são idênticos nos dois tipos, no entanto, a tabela FOR UPDATE tem uma estrutura adicional chamada %control que contém informações administrativas.

Você não pode transferir a tabela de conexões para a instrução MODIFY ENTITIES. Por isso, você precisa copiar seus dados para uma tabela interna de tipo adequado (connections_upd) antes de executar a modificação real.

Para atualizar os dados com os campos que você preencheu na determinação, você utiliza a instrução MODIFY ENTITIES. Nela, você especifica quais campos devem ser atualizados na cláusula FIELDS e transfere os dados para uma tabela interna usando o suplemento WITH. Esta tabela deve ter o tipo de dados derivados correto, que neste caso seria TYPE TABLE FOR UPDATE zsd4d400_r_connection.

A instrução MODIFY ENTITIES pode retornar mensagens que você recebe usando a cláusula REPORTED. Em seguida, você propaga essas mensagens para seu próprio business object copiando o conteúdo da tabela interna para a estrutura REPORTED do método de determinação.

Como determinar as cidades e os países

Validar o preço do voo

Neste exercício, você define e implementa uma validação para o preço do voo.

Modelo:

  • nenhum

Solução:

  • /LRN/S4D400_R_FLIGHT (definição de comportamento)
  • /LRN/BP_S4D400_R_FLIGHT (classe global)

Pré-requisitos

Você concluiu os exercícios anteriores. Você criou e preencheu a tabela de banco de dados Z##FLIGHT (onde ## é o seu número de grupo) e gerou os objetos de desenvolvimento para um serviço de IU OData.

Tarefa 1: Validar o preço

Defina e implemente uma validação para verificar se o campo Preço tem um valor positivo (nome sugerido: validatePrice). Se o valor for negativo ou igual a zero, rejeite a modificação e notifique uma mensagem de erro adequada da classe de mensagens /LRN/S4D400.

Etapas

  1. Na definição de comportamento ZR_##FLIGHT, defina uma nova validação validatePrice. Certifique-se de que a validação é sempre executada durante a operação padrão Criar, mas somente se o valor de Preço for modificado para todas as outras operações.

    Dica

    Utilize o code completion sempre que possível para inserir o código.
    1. Abra a definição de comportamento ZR_##FLIGHT.

    2. Ajuste o código da seguinte forma:

      Code Snippet
      12345
      create; update; delete; validation validatePrice on save { create; field Price; }
  2. Ative a definição de comportamento.

    1. Pressione Ctrl + F3 para ativar a definição de comportamento.

  3. Utilize uma correção rápida para criar o método de implementação de validação na classe de manipulador de comportamento.

    1. Posicione o cursor no nome da validação e selecione Ctrl + 1.

    2. Clique duas vezes na entrada Adicionar método para validação....

  4. No início do método validatePrice, declare um objeto de dados estruturado que você digitou com o tipo de linha de voo com falha (nome sugerido: failed_record). Da mesma forma, declare um objeto de dados estruturado que você digitar com o tipo de linha de reported-flight (nome sugerido: reported_record).

    Nota

    Essas estruturas serão usadas para adicionar linhas ao voo com falha e ao voo reportado, caso a validação encontre um erro.
    1. Adicione o seguinte código:

      Code Snippet
      12
      DATA failed_record LIKE LINE OF failed-flight. DATA reported_record LIKE LINE OF reported-flight.
  5. Utilize uma instrução READ ENTITIES para ler a entrada do usuário do buffer transacional. Utilize o suplemento IN LOCAL MODE e assegure que somente os campos-chave e o campo Preço sejam lidos. Use uma declaração inline para o conjunto de resultados (nome sugerido: voos).

    Nota

    Não é necessário listar os campos-chave após o suplemento FIELDS. READ ENTITIES lê sempre os campos-chave.
    1. Após as declarações, adicione o seguinte código, substituindo ## pelo seu 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 um loop sobre os dados que você acabou de ler. Utilize uma declaração inline para a área de trabalho (nome sugerido: voo).

    1. Após a instrução EML, adicione o seguinte código:

      Code Snippet
      123
      LOOP AT flights INTO DATA(flight). ENDLOOP.
  7. Dentro do loop, verifique se o componente Preço é maior que zero. Caso contrário, preencha a estrutura failed_record com a chave do voo atual e adicione-a como nova linha à tabela failed-flight. Da mesma forma, preencha a estrutura reported_record com a chave do voo atual e adicione-a como nova linha à tabela reported-flight.

    Dica

    Em business objects ativados para esboço, é recomendado que você use o componente %tky para atribuir a chave.
    1. Dentro do loop, adicione o seguinte 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 da instrução APPEND, preencha o componente %msg da estrutura reported_record com uma referência a um objeto de mensagem. Para criar o objeto de mensagem, chame o método new_message com a seguinte entrada:

    Nome do parâmetroValor
    ID'/LRN/S4D400'
    número'101'
    nível de gravidadeerro ms
    1. Ajuste o código da seguinte forma:

      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. Ative a classe.

    1. Pressione Ctrl + F3 para ativar a classe.

Tarefa 2: Testar e depurar

Defina um ponto de parada na implementação de validação. Reinicie a visualização do serviço de IU OData e modifique o preço de um voo existente. Efetue entradas válidas e inválidas e depure a validação.

Etapas

  1. Defina um ponto de parada na instrução READ ENTITIES do método validatePrice.

    1. Na implementação do método validatePrice, procure a instrução READ ENTITIES e clique duas vezes na área à esquerda do número da linha para definir um ponto de parada.

  2. Reinicie a visualização do serviço de IU OData.

    1. Feche a janela do navegador ou a guia do navegador que contém a visualização.

    2. Abra a ligação de serviço ZUI_##FLIGHT_O4. Na lista Conjunto de entidades e associação no lado direito, selecione primeiro a entrada Voo e, em seguida, Visualizar....

  3. No app, exiba a lista de voos, abra os detalhes de um dos voos e mude para o modo de modificação.

    1. Prossiga da mesma maneira que você fez em exercícios anteriores.

  4. Efetue algumas modificações no preço e, em seguida, selecione Gravar. Analise a validação no depurador.

    1. Prossiga da mesma maneira que você fez em exercícios anteriores.