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:
Selecione Arquivo→Novo→Outro… e digite mensagem no campo de filtro.
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.
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

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.
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:
- 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.
- 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.
- 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.






