sexta-feira, 16 de novembro de 2012

Ordem de execução das Regras - Parte II

Vamos para a segunda e última parte desta "série"... Bom gurizada, conforme combinado no dia primeiro de novembro (post "Ordem de Execução das Regras - Parte I"), darei continuidade a este assunto. Como, diabos, esse tal de Genexus trata a execução de regras e fórmulas especificadas nas transações. 

Hoje iremos conhecer, ou então recordarmos, as regras com eventos de disparos definidos. 

Mas que eventos de disparos são estes? 

Em alguns casos, quando programamos as regras em nossa transação, precisamos adicionar um evento para controlar o momento em que esta regra será executada, e dessa forma, controlar para que o objeto aja da forma esperada. 

Os eventos de disparos são:
  1. BeforeValidate;
  2. AfterValidate - BeforeInsert - BeforeUpdate - BeforeDelete;
  3. AfterInsert - AfterUpdate - AfterDelete;
  4. AfterLevel;
  5. BeforeComplete;
  6. AfterComplete;
Podemos visualizar na nossa figura de apoio abaixo, em qual momento cada um se executa:

Genexus Rules

Este conhecimento é essencial ao analista genexus, e é um assunto que sempre cai nas provas de certificações, por isso, vamos tentar capturar esta lógica de ordenação!

BeforeValidate

Este evento ocorre um momento antes que a informação trabalhada (cabeçalho ou linha de um grid) seja validada. Este é um evento pouco utilizado, visto que as informações digitadas na form ainda não foram validadas. Podemos utilizar para chamar procedures passando como parâmetro os próprios parâmetros recebidos através da regra parm.

AfterValidate - BeforeInsert - BeforeUpdate - BeforeDelete

Este evento ocorre após a validação da informação trabalhada (cabeçalho ou linha de um grid) e, antes da inserção física dos dados. Isso mesmo, a inserção física dos dados no banco de dados, ocorre após este evento de disparo, e não no famoso commit

Efetuar um commit, significa que um conjunto de operações realizada na base de dados, foi finalizada com sucesso. E assim, se da por finalizada uma unidade de trabalho lógica (UTL).

Preste atenção, pois os eventos especificados abaixo são idênticos:
[Regra] if insert on AfterValidate = [Regra] on BeforeInsert;
[Regra] if update on AfterValidate = [Regra] on BeforeUpdate;
[Regra] if delete on AfterValidate = [Regra] on BeforeDelete;
Porém, se especificarmos somente o evento AfterValidate, a regra será executada em todas as ações anteriores, inserção, alteração e exclusão. Cuide isto.

AfterInsert - AfterUpdate - AfterDelete

Este evento ocorre após a inserção física da informação trabalhada (seja cabeçalho ou linha de um grid).
Lembre-se então, para setarmos valores a atributos através de regras, o último momento é a regra anterior (AfterValidate). Desta regra em diante, os dados já estarão gravados no nosso banco de dados.

AfterLevel

Este evento ocorrerá após o abandono do nível (grid) trabalhado e, após a gravação física da última linha deste grid. Caso a nossa transação só possuir um grid, este evento ocorrerá no mesmo instante do evento BeforeComplete. Caso a transação possuir 2 ou mais níveis, este evento ocorrerá no mesmo número de vezes.

Exemplo, caso precisamos obrigar o usuário a inserir no mínimo uma linha do Grid, especificaríamos:
Error("....") if Count(AtributoGrid) = 0 on AfterLevel Level AtributoGrid;

BeforeComplete

Este evento ocorrerá antes de se realizar o commit, isto é, terminar a UTL trabalhada. Como visto anteriormente, este evento coincidirá com o evento AfterLevel quando só existir um nível ou então, caso possua N níveis, com o último nível criado.

AfterComplete

Este evento ocorrerá após a realização do commit.

Exemplos de utilização

Em uma transação de Clientes, desejamos emitir um relatório dos dados dos clientes nos determinados momentos: ao inserir um registro; ao atualizar um registro; e ao excluir um registro,

Inserção de novo registro

Neste caso só podemos chamar o relatório após os dados da transação terem sido gravados fisicamente na tabela. Por isso, não poderíamos utilizar o evento BeforeInsert/AfterValidate, pois os dados estariam apenas validados. Logo nossa regra seria:
Relatório.Call(ClienteId) on AfterInsert;
Se utilizássemos a regra BeforeInsert, o Id do Cliente não estaria inserido no banco de dados e nosso relatório se apresentaria vazio.
  
Atualização de um registro  - relatório dos dados antigos, antes de serem alterados

Neste caso, desejamos que o relatório seja gerado antes da gravação física dos novos dados, ou seja, um log da situação anterior à mudança. Logo nossa regra seria:
Relatorio.Call(ClienteId) on BeforeUpdate; ou então
Relatorio.Call(ClienteId) if update on AfterValidate;
Se utilizássemos a regra AfterUpdate, os novos dados já estariam sido gravados fisicamente na tabela, sendo assim, impossível de capturar sua posição anterior.

Exclusão de um registro - dados do cliente excluído do sistema

Neste caso, desejamos que o relatório seja gerado antes da exclusão ter sido realizada na tabela, para desta forma, podermos capturar todas as informações do cliente a ser excluído. Logo nossa regra seria:
Relatorio.Call(ClienteId) on BeforeDelete; ou então
Relatorio.Call(ClienteId) if delete on AfterValidate;
Caso utilizássemos a regra AfterDelete, a exclusão física já haveria sido realizada, e não existiria mais as informações sobre nosso pobre cliente.
-----------------------------------------------------------------------------------------------
Exercícios

Verdadeiro ou falso, algumas regras estão mal programadas?
FaturaData = &today on AfterInsert;
Incorreto: o último momento de assinalarmos algum valor para os atributos é o evento AfterValidate/BeforeInsert/BeforeUpdate.

Procedure.Call(FaturaData) on AfterInsert;
Correto: os dados já foram inseridos fisicamente na tabela, por isso, caso o restante da transação não apresente erro, o comando irá se executar com sucesso.

2 comentários:

  1. Ótima postagem!

    Muito obrigado por compartilhar seus conhecimentos, sempre que estou trabalhando com transações e fico com dúvida nos eventos de disparo acabo voltando aqui...

    Novamente, obrigado

    Raphael Gonçalves

    ResponderExcluir
    Respostas
    1. Obrigado Raphael, esses comentários nos motivam a continuar compartilhando para a comunidade Genexus. Forte Abraço.

      Eduardo

      Excluir