05 ordem execucaoregrase-formulas-cursogxxbr

26

Upload: cristiano-rafael-steffens

Post on 27-Jul-2015

532 views

Category:

Technology


1 download

TRANSCRIPT

Page 1: 05 ordem execucaoregrase-formulas-cursogxxbr
Page 2: 05 ordem execucaoregrase-formulas-cursogxxbr

A forma de programar o comportamento das transações é definindo regras, escritas de formadeclarativa. Quando temos cálculos para efetuar, podemos optar pela alternativa de definir atributosfórmulas.

Em nenhum momento, o programador GeneXus especifica a seqüência de execução das regras efórmulas definidas em uma transação. Quando for gerar, o GeneXus determina as dependênciasexistentes entre as regras e fórmulas definidas.

Vamos supor que estamos definindo uma aplicação para uma empresa que vende determinadosprodutos, e que conta com um serviço de entrega a domicílio que leva a mercadoria a seus clientes.E definimos entre outras, as seguintes 5 transações:

“Customer” (para registrar os clientes da empresa)“Category” (as que pertencem cada cliente)

“Shipping” (envios: guarda um histórico de custos de envio)“Invoice” (faturas emitidas aos clientes)

“Product” (produtos que são vendidos pela empresa)

Ressaltamos a estrutura da transação “Invoice”, com seus atributos fórmulas e suas regrasdeclaradas.

Em que ordens serão disparadas as regras e fórmulas da transação “Invoice”?

Page 3: 05 ordem execucaoregrase-formulas-cursogxxbr

No momento de gerar o programa associado na transação “Invoice”, o GeneXus determinará asdependências existentes entre as regras e fórmulas definidas; e construirá logicamente uma árvore dedependências (ou árvore de avaliação) que determinará a seqüência de avaliação.

Podemos imaginar que a árvore é executada de baixo para cima, cada vez que alteramos algum valorde um atributo, se executam todas as regras e fórmulas que dependem desse atributo (e que na árvorese encontram para cima).

Por exemplo, alterando a quantidade de uma linha de uma fatura (InvoiceDetailQuantity), como esteatributo interfere na fórmula que calcula o valor da linha (InvoiceDetailAmount), esta fórmula serádisparada novamente. Para alterar o valor de uma linha, a fórmula é disparada novamentecorrespondendo ao subtotal da fatura (InvoiceSubTotal) e como conseqüência, também deverá serrecalculada a fórmula correspondente ao desconto (InvoiceDiscount), já que depende do subtotal.Deverá ser disparada novamente a fórmula correspondente ao total da fatura (InvoiceTotal) já quedepende tanto do valor de InvoiceSubTotal como do valor de InvoiceDiscount. Por último, por alterar ototal, também será disparada a regra Add(InvoiceTotal, CustomerTotalPurchases).

Além de serem disparadas todas as fórmulas e regras envolvidas na parte direita da Árvore desde oatributo InvoiceDetailQuantity, também são disparadas as fórmulas e regras envolvidas na parteesquerda. Ou seja, ao alterar o valor do atributo InvoiceDetailQuantity, será disparada novamentetambém a regra Subtract(InvoiceDetailQuantity, ProductStock); e em conseqüência, por modificar estaregra o valor do atributo ProductStock verifica a necessidade de disparar a regra Error(‘InsufficientStock’’) if ProductStock < 0;

Concluindo, as regras e fórmulas que se definem numa transação estão inter-relacionadas e GeneXusdetermina as dependências entre elas assim como sua ordem de avaliação.

Observemos as 2 últimas regras definidas:Subtract(InvoiceDetailQuantity, ProductStock);Error(‘Insufficient Stock’) if ProductStock < 0;

Page 4: 05 ordem execucaoregrase-formulas-cursogxxbr

Estas regras estão inter-relacionadas porque envolvem o atributo ProductStock. Agora, enquanto que a segundasomente consulta seu valor, a primeira o atualiza. Então, a regra que atualiza o atributo será a que vai disparar oprimeiro, e em seguida dispara a que o consulta.

Toda regra que atualize o valor de um atributo, será disparada antes que uma regra que o consulte (isto pode serobservado claramente na árvore). Por este motivo é que a regra Error consulta se o atributo ProductStock ficoucom valor negativo; porque como sabemos que a subtração será realizada primeiro,.

Na programação clássica primeiro consulta-se o estoque, a subtração é realizada quando ele for suficiente. Por issoquem está aprendendo GeneXus pode intuitivamente escrever a regra: Error(Insufficient Stock’) ifInvoiceDetailQuantity > ProductStock. Esta sintaxe é correta, não é correta sua lógica, já que como temosexplicado, na árvore de avaliação determinada pelo GeneXus primeiro é disparada a regra Subtract e depois aregra Error; portanto temos que definir que se dispare a mensagem de error se o estoque ficou o stock com valornegativo, já que será executado a subtração no momento de consultar o valor de ProductStock.

Assim que a regra deve definir é:

Error(‘Insufficient Stock’) if ProductStock < 0;

E não:

Error('Insufficient Stock') if InvoiceDetailQuantity > ProductStock;

Quando se dispara uma regra Error, se detêm qualquer atualização da base de dados e desarma a árvore deavaliação, ficando no estado anterior ao se produzir o erro. Seguindo o exemplo que estamos vendo, se aodisparar a regra Subtract o stock que ficará negativo, se dispararia a regra Error. Como conseqüência ao sedisparar a regra Error, o Subtract que foi executado é desfeito, assim como todas as demais regras e fórmulas quetenham executado (recálculo dos atributos InvoiceDetailAmount, InvoiceSubTotal, ...., CustomerTotalPurchases).

Page 5: 05 ordem execucaoregrase-formulas-cursogxxbr

Na maioria dos casos a ordem de execução das regras definida pelo GeneXus a partir de nossasespecificações é o desejado. Porém em alguns casos podemos querer alterar o momento de disparode uma Regra.

Exemplo:

Definimos uma transação para registrar as faturas que recebemos de nossos fornecedores.O identificador do primeiro nível é composto pelo código do fornecedor e o número de fatura, já que onúmero de fatura não nos serve como identificador único, porque fornecedores distintos podem repetiro mesmo número de fatura.

Para cada fatura de um fornecedor que inserimos, nos interessa controlar que o total que venhaescrito na fatura (e que será digitado no atributo InvoiceEntTotal) seja correto. Para fazer estecontrole, definimos o atributo InvoiceCalcTotal como fórmula verticalSUM(InvoiceDetailAmount), e agregamos uma regra Error que será disparada se não coincidir osvalores dos atributos InvoiceEntTotal e InvoiceCalcTotal:

Error(‘The calculated total doesn’t match with the entered total') if InvoiceCalcTotal <>InvoiceEntTotal;Se construirmos a árvore de avaliação correspondente as fórmulas e regra que definimos nestatransação:

Page 6: 05 ordem execucaoregrase-formulas-cursogxxbr

vemos que as dependências indicam que cada vez que são inseridos, modificados ou eliminados valores dos atributosInvoiceDetailAmount e InvoiceDetailQuantity nas linhas, recalcula-se o valor do atributo InvoiceDetailAmountcorrespondente; em conseqüência, recalculamos o valor do atributo fórmula InvoiceCalcTotal que temos definido parater o total calculado da fatura; e como o atributo fórmula InvoiceCalcTotal está envolvido na condição de disparo daregra Error, cumpre a dita condição de disparo e dispara a regra Error(‘The calculated total doesn’t match with theentered total’) if InvoiceCalcTotal <> InvoiceEntTotal;

Agora, prestamos atenção a condição de disparo InvoiceCalcTotal<>InvoiceEntTotal vai ser cumprida repetidamentena medida em que o operador vai inserindo as linhas, porque para cada linha que é inserida, calcula-se o valor doatributo fórmula InvoiceDetailAmount da linha, e como consequência é recalculado o valor do atributo fórmulaInvoiceCalcTotal. Mas o valor calculado do atributo InvoiceCalcTotal não coincidirá com o valor inserido no atributoInvoiceEntTotal até que não tenham ingressado todas as linhas da fatura; então, dispara-se a regra Error(‘Thecalculated total doesn’t match with the entered total’) if InvoiceCalcTotal <> InvoiceEntTotal;.

Concluímos então que neste caso, não nos serve o determinado na árvore de avaliação, já que não queremos queseja analisada a condição de disparo da regra Error cada vez que o operador insira, altere ou elimine as linhas, e simnecessitamos que seja analisada quando o usuário tenha terminado trabalhar com todas as linhas da fatura.

GeneXus oferece eventos ou momentos de disparo nas transações, que ocorrem antes ou depois de determinadaação, como a gravação do cabeçalho, ou de uma linha. As regras das transações podem serem condicionadas de talmaneira que sejam disparadas no momento específico que ocorre algum desses eventos de disparo.

Seguindo o exemplo visto, existe um evento de disparo que ocorre assim que entramos num nível e saímos domesmo. A sintaxe deste evento de disparo é: AfterLevel Level Atributo, devendo Atributo um atributo pertencenteao nível interagido e que se abandona.

De modo que a regra Error de nosso exemplo, agregaríamos este evento de disparo, e ficaria definida da seguinteforma:

Error(‘The calculated total doesn’t match with the entered total’) if InvoiceCalcTotal<>InvoiceEntTotal On AfterLevelProductId;

Agregando este evento de disparo a regra controlamos o que se deseja no momento adequado.

Além deste evento de disparo, existem outros que veremos em seguida.

Page 7: 05 ordem execucaoregrase-formulas-cursogxxbr

No momento da confirmação da transação, ocorre uma série de ações que é necessário para poderprogramar corretamente o comportamento das regras.Para uma transação de dois níveis, poderíamos enumerá-las como segue:

• validação dos dados do cabeçalho• gravação física do cabeçalho (seja inserção, modificação ou eliminação)• validação dos dados da primeira linha• gravação física dos dados da primeira linha• validação dos dados da segunda linha• gravação física dos dados da segunda linha• …• validação dos dados da n-ésima linha• gravação física dos dados da n-ésima linha• commit

A ação de “validação dos dados do cabeçalho” ocorre após todos serem validados e cada um dos camposinformados no cabeçalho. Observar que neste ponto já foi disparado todas as regras que correspondiamaos atributos do cabeçalho e que não tinham evento de disparo associado (exemplo: Default(InvoiceDate,&today)). Imediatamente depois será gravado o registro correspondente ao cabeçalho.

Análogo é o caso das linhas: “a validação dos dados de uma linha” ocorre após todos serem validados ecada um dos dados da linha, e também após terem sido disparadas todas as regras correspondentessegundo a árvore de avaliação (exemplo: subtract( InvoiceDetailQuantity, ProductStock)). Imediatamentedepois desta ação de validação, será gravado fisicamente o registro correspondente linha.

Cada transação, ao terminar de trabalhar com um cabeçalho e suas linhas, realiza um commit (éautomático). Será colocado no código gerado por GeneXus, exceto se o analista especifique o contrário,como veremos mais adiante. Isto é, se os dados de duas faturas distintas forem ingressados utilizando atransação “Invoice”, após serem ingressados os dados da primeira, os registros serão comitados, e depoisserá ingressado o segundo, ao qual seus registros serão comitados.

Os eventos de disparo de regras permitem condicionar o disparo de uma regra da transação para que seexecute antes ou depois de alguma das ações que acabamos de enumerar. Veremos quando ocorre cadaevento de disparo.

Page 8: 05 ordem execucaoregrase-formulas-cursogxxbr

Evento de disparo: BeforeValidate

Este evento de disparo ocorre um pouco antes da informação da instancia que se trabalhe (cabeçalho oulinha) seja validada (ou confirmada). Isto é, ocorrerá antes da ação de “validação do cabeçalho” ou“validação da linha”, correspondente. Observar que aqui também haverão disparadas todas as regrassegundo a árvore de avaliação que não estejam condicionadas com nenhum evBeforeento de disparo.

Eventos de disparo: AfterValidate, BeforeInsert, BeforeUpdate, BeforeDelete

O evento de disparo AfterValidate permite definir que uma regra seja executada imediatamente antes deque gravemos fisicamente cada instancia do nível ao qual está associada a regra, na tabela físicacorrespondente e depois de ter validado os dados desta instancia.

Em outras palavras, agregando o evento de disparo AfterValidate a uma regra, a mesma executará, paracada instancia do nível ao qual esteja associada a regra, imediatamente antes de que a instancia sejagravada fisicamente (seja quando insere, altere ou elimine) como registro na tabela física associadaao nível.

EXEMPLOS

1. Tem vezes que não contamos com a possibilidade de utilizar a Propriedade Autonumber para numerarde forma automática e correlativa os atributos que são chave primária simples. Tal funcionalidade éprevista pelos administradores de base de dados (DBMSs) e o GeneXus a aproveita e permite usá-la;nos casos em que não trabalhamos com um administrador de base de dados, não temos apossibilidade de selecionar esta facilidade.

Nesses casos que não contamos com a possibilidade de utilizar a Propriedade Autonumber enecessitamos numerar de forma automática e correlativa certos atributos, devemos resolver nós mesmosna programação. Para fazê-lo somente definindo uma transação contendo ao menos dois atributos, umpara armazenar um literal e outro para armazenar o último número atribuído automaticamente ao atributodescrito pelo literal1; a transação vai fazer com que seja criada uma tabela, e temos que definir umprocedimento que consulte essa tabela, obtenha o último número atribuído para o atributo a ser numerado,some um e devolva o próximo número, além de atualizá-lo na tabela.

Para chamar ao procedimento de numeração automática se deve definir nas transações que o requerem aseguinte regra:

CustomerId = PGetNumber.udp( ‘CUSTOMER’ ) if Insert on AfterValidate;

Neste caso se está querendo serializar o atributo CustomerId da transação “Customer”

Do mesmo modo, se queremos serializar o identificador de faturas, escreveríamos na transação “Invoice”com a seguinte regra:

InvoiceId = PGetNumber.udp( ‘INVOICE’ ) if Insert on AfterValidate;

Desta forma definimos que se efetuam numerações automáticas nas transações unicamente quando serealizem inserções (pela condição de disparo: if Insert) e imediatamente antes do registro ser gravadofisicamente cada instancia a ser inserida (pelo evento de disparo: on AfterValidate) através do primeironível da transação (porque nas duas regras de chamadas que foram mostradas, tem somente um atributoenvolvido que pertence ao primeiro nível das transações “Customer” e “Invoice” respectivamente).

O motivo pelo qual agregamos o evento de disparo on AfterValidate a estas regras é para chamar oprocedimento de numeração automática imediatamente antes de que seja inserido o registro na base dedados e depois da validação, tentando desta forma ter o maior grau de segurança possível ao númeroatribuído que será utilizado (e não perder números). Caso a regra fosse disparada sem ter condição, e nocaso de faltar alguma validação dos dados do cabeçalho. A resposta é simples: um número seria perdido.Ou seja, se o número da fatura anterior for 5 e o usuário quer informar a seguinte fatura, a regra deatribuição com udp chama o procedimento de numeração que seria disparado assim que ingressar natransação com modo insert, porque o primeiro atributo do cabeçalho é utilizado. O procedimento devolveriao número 6, e se ao validar os dados do cabeçalho encontrar algum error que não permita continuar com oprocesso, abandonar a transação, por exemplo, esse número 6 seria perdido e a próxima fatura, quedeveria ter o número 6 não o terá, e sim o número 7.

________________________________________________________________________________________1 Quando vimos a regra serial falamos este tema de numeração de cabeçalho, com a transação "Number” que era a que tinha oliteral: NumberCode e o último número atribuído a transação correspondente a esse literal: NumberLast

Page 9: 05 ordem execucaoregrase-formulas-cursogxxbr

Existem 3 eventos de disparo que ocorrem no mesmo momento que o AfterValidate, mas já possuem o modo de forma intrínseca.São eles: BeforeInsert, BeforeUpdate e BeforeDelete.É equivalente escrever a regra apresentada como:

InvoiceId = PGetNumber.udp( 'INVOICE') on BeforeInsert;

Observar que aqui é redundante condicionar a regra a “If Insert”. Portanto, as seguintes equivalências são válidas:

on BeforeInsert ∼ If Insert on AfterValidateon BeforeUpdate ∼ If Update on AfterValidateon BeforeDelete ∼ If Delete on AfterValidate

Se tivermos um esquema das ações que rodeiam o disparo do evento, ficam claros os dois sinônimos escolhidos para este evento(AfterValidate e BeforeInsert para modo insert)

VALIDAÇÃO DOS DADOSAfterValidate – BeforeInsert – BeforeUpdate – BeforeDeleteGRAVAÇÃO DO REGISTRO (insert, update, delete segundo corresponda)

2) Se definirmos uma regra em que incluímos também o evento de disparo on AfterValidate, ou on BeforeInsert, BeforeDelete,BeforeUdate, mas a diferença dos exemplos recém vistos, é referenciado na regra pelo menos um atributo do segundo nível datransação na qual está definindo a regra, a mesma estará associada ao segundo nível1. Portanto, a regra executará imediatamenteantes que seja gravada fisicamente cada instancia correspondente ao segundo nível da transação.

Eventos de disparo: AfterInsert, AfterUpdate, AfterDelete

Assim como existe um evento de disparo que permite definir que determinadas regras sejam executadas imediatamente antes queseja produzida a gravação física de cada instancia de um nível (AfterValidate, BeforeInsert, BeforeUpdate e BeforeDelete), tambémexistem eventos de disparo para definir que certas regras sejam executadas imediatamente depois de que sejam inseridas,modificadas ou eliminadas fisicamente instancias de um nível. Estes eventos são AfterInsert, AfterUpdate e AfterDelete.

O evento de disparo AfterInsert permite definir que uma regra execute imediatamente depois de que seja inserida fisicamente cadainstancia do nível ao qual está associada a regra; o AfterUpdate depois de atualizar fisicamente a instancia, e o AfterDelete depoisde eliminar.

EXEMPLOS

Vamos supor que na transação “Customer” queremos chamar um relatório que realize a impressão dos dados de cada cliente como qual trabalhamos por meio da transação.

Em que momento devemos realizar as chamadas ao relatório a partir da transação?

Caso 1: RPrintCustomer.call( CustomerId ) on AfterValidate;

Não é adequado agregar-lhe este evento de disparo a regra de chamadas ao relatório, porque o mesmo seria chamadoimediatamente antes da gravação física de cada cliente. Em conseqüência, o relatório não encontraria o cliente com seus dadosna tabela CUSTOMER (caso estivesse inserindo um cliente por meio da transação), ou o encontraria com seus dadosdesatualizados (caso estivesse modificando um cliente por meio da transação). Se na alteração estivesse eliminando um cliente pormeio da transação, o relatório encontraria os dados do cliente na tabela CUSTOMER e os listaria justamente antes da atualizaçãofísica (eliminação).

Caso desejarmos emitir uma lista com os dados de cada cliente que forem eliminados, seria adequado definir a seguinte regra:

RPrintCustomer.call( CustomerId ) on BeforeDelete;ou equivalente:RPrintCustomer.call( CustomerId ) if delete on AfterValidate;

__________________________________________________________________________________________________1 Existe outra forma de provocar que uma regra que contem atributos de um nível determinado, se dispare no nível seguinte, pormeio de cláusula Level que foi mencionado quando vimos conceitos importantes sobre as regras de transações.

�����

Page 10: 05 ordem execucaoregrase-formulas-cursogxxbr

para restringir o disparo da regra unicamente quando estamos eliminando um cliente, porque é o único caso em queseria correto utilizar o evento de disparo AfterValidate (já que justamente necessitamos emitir o relatório antes daeliminação).

Caso 2: RPrintCustomer.Call( CustomerId ) on AfterInsert;

O evento de disparo AfterInsert ocorre imediatamente depois de que inserimos fisicamente cada instancia associadaa certo nível da transação (neste caso, como o único atributo envolvido na regra é CustomerId, trata-se de uma regraassociada ao primeiro e único nível da transação “Customer”).

Como indica claramente pelo seu nome, o evento de disparo AfterInsert somente ocorre ao inserir uma novainstancia (precisamente após ser inserida como registro físico). Utilizando ele quando se agrega o evento de disparoon AfterInsert a uma regra, não é necessário agregar-lhe a condição de disparo if insert.

É correto agregar este evento de disparo a regra de chamadas ao relatório, já que o relatório seria chamadoimediatamente depois de que fosse inserido fisicamente cada cliente. Assim que o relatório encontrar o clientecom seus dados na tabela CUSTOMER e os imprime.

O que deve ficar claro é que com esta definição, o relatório é chamado unicamente logo que realizar inserções.

Caso 3: RPrintCustomer.Call( CustomerId ) on AfterUpdate;

O evento de disparo AfterUpdate ocorre imediatamente depois que é atualizada fisicamente cada instancia associadaa certo nível da transação (neste caso, como o único atributo envolvido na regra é CustomerId, se trata de uma regraassociada ao primeiro e único nível da transação “Customer”).

É adequado agregar neste evento de disparo a regra de chamadas ao relatório, já que o relatório é chamadoimediatamente depois que for atualizado fisicamente um cliente. Assim que o relatório encontrar o cliente comseus dados atualizados na tabela CUSTOMER e os imprimir.

O relatório será chamado unicamente após realizar as atualizações.

Caso 4: RPrintCustomer.Call( CustomerId ) on AfterDelete;

O evento de disparo AfterDelete ocorre imediatamente depois da eliminação física de cada instancia associada acerto nível da transação (neste caso, como o único atributo envolvido na regra é CustomerId, se trata de uma regraassociada ao primeiro e único nível da transação “Customer”).

Não é adequado agregar este evento de disparo a regra de chamadas ao relatório, porque o relatório é chamadoimediatamente depois da eliminação física de cada cliente. Em conseqüência, o relatório não encontra o clientecom seus dados na tabela CUSTOMER.

Caso 5: RPrintCustomer.Call( CustomerId ) on AfterInsert, AfterUpdate;RPrintCustomer.Call( CustomerId ) if delete on AfterValidate;

Para finalizar, estas duas regras são adequadas para chamar um relatório na transação “Customer”, com o objetivo deimprimir os dados de cada cliente com qual trabalhar, abrangendo os três modos de trabalho.

Como podemos observar na primeira regra, é possível incluir vários eventos de disparo separados por vírgula, quandoos mesmos aplicam a uma mesma regra.

Isto é, é o mesmo que definir duas regras independentes:

RPrintCustomer.Call( CustomerId ) on AfterInsert;RPrintCustomer.Call( CustomerId ) on AfterUpdate;

que esta regra:

RPrintCustomer.Call( CustomerId ) on AfterInsert, AfterUpdate;

Page 11: 05 ordem execucaoregrase-formulas-cursogxxbr

Caso 6: Se definirmos uma regra a qual incluímos o evento de disparo on AfterInsert, mas a diferença dos exemplosvistos recentemente, é referenciada na regra pelo menos um atributo do segundo nível da transação na qual estamosdefinindo a regra, a mesma estará associada ao segundo nível. Portanto, a regra é executada imediatamente depoisde que inserimos fisicamente cada instancia correspondente ao segundo nível da transação.

Analogamente é o caso de disparo de on AfterUpdate e on AfterDelete.

Ampliamos o esquema que havíamos efetuado antes, das ações que rodeiam aos eventos de disparos visto até agora:

VALIDAÇÃO DOS DADOSAfterValidate – BeforeInsert – BeforeUpdate – BeforeDeleteGRAVAÇÃO DO REGISTRO (insert, update, delete segundo corresponda)AfterInsert – AfterUpdate – AfterDelete

Este esquema se repete para cada instancia do nível. Por exemplo, pensamos no ingresso das linhas de uma fatura.Este esquema ocorre para cada linha, podemos pensar num loop que se repete até que a última linha seja gravada.

A ação depois da última linha seria gravada é quando sai desse nível (neste caso as linhas da fatura). E depois dessaação, exceto que tenha outro nível, nesse caso voltaria o esquema anterior, ocorrerá o commit que é a última ação deexecução.

Entre a ação de abandonar o nível, e o commit temos um evento (que admite dois nomes distintos) e outro para depoisdo commit. São o que veremos na continuação mas que já vamos mostrar no esquema:

VALIDAÇÃO DOS DADOS CABEÇALHOAfterValidate – BeforeInsert – BeforeUpdate – BeforeDelete

GRAVAÇÃO DO REGISTRO (insert, update, delete segundo corresponda)AfterInsert – AfterUpdate – AfterDelete

VALIDAÇÃO DOS DADOS LINHAAfterValidate – BeforeInsert – BeforeUpdate – BeforeDelete

GRAVAÇÃO DO REGISTRO (insert, update, delete segundo corresponda)AfterInsert – AfterUpdate – AfterDelete

ABANDONAR NÍVEL 2AfterLevel - BeforeCompleteCOMMITAfterComplete

�����

�����

����

Page 12: 05 ordem execucaoregrase-formulas-cursogxxbr

Eventos de disparo: AfterLevel, BeforeComplete

O evento de disparo AfterLevel permite definir que uma regra seja executada imediatamente depois de terminar de interagirdeterminado nível.SINTAXE: regra [if condição de disparo] [on AfterLevel Level atributo];

ONDE:regra: é uma regra das permitidas em transaçõescondição de disparo: é uma expressão booleana que permite envolver atributos, variáveis, constantes e funções, assim como osoperadores Or, And, Not.atributo: é um atributo pertencente ao nível para o qual se deseja que depois de ser iterado, se execute a regra.

FUNCIONALIDADE:

Se o atributo que especificamos na continuação do evento de disparo AfterLevel pertencer ao segundo nível da transação, a regraserá executada quando terminar de interagir com todas as linhas do segundo nível.

E se o atributo especificado em seguida do evento de disparo AfterLevel pertencer ao primeiro nível, - seguindo o mesmo conceito - aregra será executada quando tenha terminado de interagir com todos os cabeçalhos. Observar que isto ocorre no final de tudo, ouseja, uma vez que tivermos inserido todos os cabeçalhos e suas linhas e fechado a transação (nesse momento terão interagido todosos cabeçalhos). Portanto, se o atributo especificado pertencer ao primeiro nível, à regra será disparada uma vez somente antes doEvento Exit (é um evento que executa uma vez quando fechamos uma transação em tempo de execução, como veremos).

Exemplo: Rever o exemplo apresentado anteriormente, onde tínhamos uma transação para representar as Faturas dos fornecedores,e onde tínhamos que controlar que o total calculado de cada fatura coincida com o total informado. Tínhamos a regra:

Error(‘The calculated total doesn’t match with the entered total ') if InvoiceCalcTotal<>InvoiceEntTotal;

que necessitamos que se dispare depois de todas as linhas da fatura do Fornecedor serem informadas. Portanto, o evento de disparoapropriado será AfterLevel att, onde att pode ser qualquer atributo das linhas.

O evento de nome BeforeComplete, neste caso, coincide com o AfterLevel. Se observarmos o esquema apresentado na páginaanterior, podemos ver que o tempo que tem entre sair do último nível e a realização do commit é o instante que ocorrem esteseventos. São 02 (dois) nomes para nos referimos ao mesmo.

Cuidado que isto é sempre assim e quando o nível abandonado é o último. Por exemplo uma transação com dois níveis paralelos. Seagregamos ao cliente suas direções de mail e seus números telefônicos (pode ter vários):

CustomerId*CustomerName…{CustomerPhone*…}{CustomerEMail*…}

O momento em que deverá disparar uma regra condicionada a: On AfterLevel Level CustomerPhone NÃO COINCIDIRÁ com o deuma regra condicionada a on BeforeComplete.

Enquanto que a primeira se dispara ao sair do nível dos telefones, e antes de entrar a validar todos os emails, a segunda se dispararádepois de sair deste último nível.Neste caso o evento BeforeComplete coincidirá com o AfterLevel Level CustomerEMail.

Evento de disparo: AfterComplete

Este evento corresponde ao instante de tempo que acontece o commit. Falaremos mais deste evento umas páginas adiantes, quandoestudarmos integridade transacional.Se abrir a transação de faturas, se ingressam 3 faturas (cabeçalho e suas respectivas linhas) e fecha a transação, ocorrerão 3commits (um no final de cada ingresso de cabeçalho + linhas) e 3 eventos AfterComplete.

Page 13: 05 ordem execucaoregrase-formulas-cursogxxbr

O seguinte exemplo pretende mostrar visualmente em que momentos serão disparadas as regras efórmulas definidas numa transação.

O disparo de regras e fórmulas irá sendo feito de acordo com a árvore de avaliação, seguindo aordem que esta determina.

Page 14: 05 ordem execucaoregrase-formulas-cursogxxbr

Regras stand aloneAs regras stand alone são aquelas que:1. Podem executar-se com a informação prevista pelos parâmetros recebidos.2. Não dependem de nada para serem executadas.

Exemplos de regras stand alone (poder executar com a informação prevista pelos parâmetros):· &A = parâmetro2;· Msg( ‘...’ ) if parâmetro1 = 7;

Exemplos de regras stand alone (não dependem de nada para serem executadas) :· msg( ‘You are in the invoice transaction’);· &A = 7;

Portanto, são as primeiras regras que podem ser executadas.Depois da execução das regras stand alone, se executam as regras associadas ao primeiro nível datransação, que não tenham evento de disparo definido, seguindo a ordem de dependências determinadopor GeneXus (assim como as fórmulas associadas ao primeiro nível). Como exemplo, se dispara a regra:“Default( InvoiceDate, &Today);”Depois de executadas as regras mencionadas para o cabeçalho, serão executadas todas as regras quetenham como evento de disparo BeforeValidate, já que imediatamente depois ocorre a ação de validação(ou confirmação) da informação desse primeiro nível.

Imediatamente depois da validação do primeiro nível se executam as regras associadas ao primeiro nível datransação que incluam em sua definição o evento de disparo AfterValidate, ou os BeforeInsert,BeforeUpdate, BeforeDelete, dependendo do modo em que esteja.

Por exemplo: Se não podemos serializar as faturas com a propriedade Autonumber porque o DBMSescolhido não suporta:

InvoiceId = PGetNumber.udp(‘INVOICE’) on BeforeInsert;

Page 15: 05 ordem execucaoregrase-formulas-cursogxxbr

Após a execução das regras associadas ao primeiro nível com alguns destes eventos de disparo executa-se aação de gravação; ou seja, que gravará fisicamente a instancia correspondente ao primeiro nível da transaçãocomo registro físico na tabela correspondente (neste exemplo, na tabela: INVOICE).

Imediatamente depois de ter gravado a instancia:· se a gravação correspondeu a uma inserção: executarão as regras associadas ao primeiro nível da transaçãocom evento de disparo AfterInsert.· se a gravação correspondeu a uma atualização: executarão as regras associadas ao primeiro nível datransação com evento de disparo AfterUpdate.· se a gravação correspondeu a uma eliminação: executarão as regras associadas ao primeiro nível datransação com evento de disparo AfterDelete.

Sendo uma transação de dois níveis, como neste caso, serão executadas para cada uma daslinhas:

Em primeiro lugar, as regras associadas ao segundo nível da transação que não tenham evento dedisparo definido, seguindo a ordem de dependências determinado pelo GeneXus (assim como asfórmulas associadas ao segundo nível). Exemplos disso são a regra:

Subtract( InvoiceDetailQuantity, ProductStock );

a fórmula

InvoiceDetailAmount = InvoiceDetailQuantity*ProductPrice.

Depois das regras mencionadas executadas para uma linha, serão executadas todas as regras quetenham como evento de disparo BeforeValidate, visto que imediatamente depois ocorre avalidação da linha; isto é uma ação que ocorre depois de terminar de trabalhar com a linha.

Imediatamente depois da validação da linha, serão executadas as regras associadas ao segundonível da transação que incluam em sua definição algum dos eventos de disparo: AfterValidate,BeforeInsert, BeforeUpdate, BeforeDelete.

Em seguida a execução das regras associadas ao segundo nível com algum destes eventos dedisparo será executada a ação de gravação; isto é, gravará fisicamente a instancia correspondentea linha como registro física na tabela correspondente (neste exemplo, na tabela: INVOICEDETAIL).

Imediatamente depois de ter gravado a instancia correspondente a linha como registro físico natabela correspondente:

• se a gravação correspondeu a uma inserção: são executadas as regras associadas ao segundonível da transação com evento de disparo AfterInsert.• se a gravação correspondeu a uma atualização: são executadas as regras associadas aosegundo nível da transação com evento de disparo AfterUpdate.• se a gravação correspondeu a uma eliminação: são executadas as regras associadas ao segundonível da transação com evento de disparo AfterDelete.

Todas estas operações sombreadas de cinza claro, são executadas na ordem descrita, para cadauma das linhas.Após a interação de todas as linhas, podemos supor a existência de uma ação que poderíamoschamar abandono do segundo nível. Após dela são executadas as regras definidas com eventode disparo AfterLevel Level Atributo do 2do nível. Se não existir outro nível, como é o caso doexemplo, então coincidirá com o evento de disparo BeforeComplete

Page 16: 05 ordem execucaoregrase-formulas-cursogxxbr

Declaração Importante: Todas as operações sombreadas, tanto de cor clara como de cor escura, executam-seunicamente quando for uma transação de dois níveis; de modo que se for uma transação de um nível, sabemosque tais operações não são executadas. O motivo dos dois sombreados distintos, é para diferenciar o conjunto deoperações que são executadas para cada uma das linhas (sombreado cor clara) das operações que sãoexecutadas somente uma vez ao terminar de interagir com as linhas (sombreado com cor mais escura).Posteriormente, explicaremos as demais operações que são executadas, seja em uma transação de um nível oude dois.

Após de ser executada todas as operações explicadas até o momento, um commit é efetuado.

Na continuação serão executadas as regras com evento de disparo AfterComplete.

É de fundamental importância que fique claro que todas as operações explicadas, serão executadas na ordem quefoi descrito, para cada fatura com a qual se trabalhe por meio da transação “Invoice” (seja quando se insere,modifique ou elimine)

Pode ser útil saber que serão ressaltadas em negrito as ações cada vez que se tenha mencionado. As mesmassão: validação, gravação, abandono do segundo nível (sair do segundo nível) e commit.

É indispensável assimilar fortemente em que ordem se executam as regras em uma transação, quais são oseventos de disparo disponíveis para atribuir, quando são disparadas exatamente, e que ações ocorrem antes edepois de cada evento de disparo, já que somente conhecendo bem todo este tema, poderá programar ocomportamento das transações adequadamente. É fácil compreender que se necessitamos programardeterminados controles ou ações nas transações, teremos que saber bem se será feito antes de gravar ocabeçalho, depois de gravar o mesmo, para cada uma das linhas depois que se tenham gravado, ou antes, depoisdo commit, ou antes, portanto é fundamental ter bem claro todo este tema.

Page 17: 05 ordem execucaoregrase-formulas-cursogxxbr
Page 18: 05 ordem execucaoregrase-formulas-cursogxxbr
Page 19: 05 ordem execucaoregrase-formulas-cursogxxbr

Regras com o mesmo evento de disparoQuando em uma transação definimos duas ou mais regras com o mesmo evento de disparo, e nãoexiste nenhuma dependência entre elas, as mesmas serão executadas respeitando a ordem dedefinição.

Exemplos:1) Se definem as seguintes regras em uma transação:

‘xxx’.Call() on AfterComplete;‘yyy’.Call() on AfterComplete;

Como as duas regras definidas estão condicionadas ao mesmo evento de disparo, e não existenenhuma dependência entre elas, elas serão executadas na mesma ordem em que foram escritas.

2) Em uma transação, caso seja necessário chamar a um procedimento que realiza determinadavalidação e retorna um valor ‘S’ ou ‘N’; e se o valor devolvido é ‘N’, aparecerá uma mensagem de erro.

Para resolver isto, avaliaremos duas possibilidades:

2.1) Definir as regras:Pgmname.call(CustomerId, &flag) on AfterComplete;

Error(“ “) if &flag=”N” on AfterComplete;

Page 20: 05 ordem execucaoregrase-formulas-cursogxxbr

2.2) Ou definir as regras:

&flag = Pgmname.udp(CustomerId) on AfterComplete;Error(“ “) if &flag = ”N” on AfterComplete;

Na primeira alternativa, temos definida uma regra call e uma regra error. Ambas regras tem o mesmo eventode disparo, e aparentemente existiria dependência entre elas, já que a regra de error está condicionada aovalor da variável &flag, e a variável &flag se passa por parâmetro na regra call.

Todavia, a dependência pode parecer evidente porque no procedimento programamos a variável &flag, desaída, na seção de regras da transação - que é onde encontram-se as regras vista até então -, oespecificador do GeneXus não pode saber se os parâmetros passados em um call são de entrada, de saída,ou de entrada-saída; em conseqüência o especificador não encontrará inter-dependência entre as regras calle error, já que a variável &flag poderia ser passada como variável de entrada ao procedimento, e nesse casopor Exemplo, não haveria uma dependência de que primeiro deve-se executar a regra call e depois a regraerror.

Concluindo, não se detectam dependências entre as regras call e error da alternativa 2.1), porque asmesmas serão disparadas na Ordem em que estão escritas. É importante ver que, se as regras call e errorestiverem escritas em ordem inversa (primeiro a regra error e depois a regra call), em muitos casos ocomportamento não será o esperado.

A respeito da segunda alternativa, observemos que consiste em uma regra udp e uma regra error. Ambasregras tem o mesmo evento de disparo, e neste caso se existir dependência entre elas, já que a regra errorestá condicionada ao valor da variável &flag, e como as chamadas ao procedimento realizam-se com udp,para o especificador do GeneXus fica claro que a variável &flag volta modificada do procedimento; portanto, oespecificador do GeneXus entende que primeiro deve-se disparar a chamada ao procedimento com udp edepois a regra error, porque a variável &flag é carregada mediante a chamada ao procedimento com udp, elogo que esta variável tenha valor, é que será avaliada a necessidade de disparar a regra error, ou não.

No caso 2.2), então, independentemente da ordem de definição de ambas as regras, a chamada aoprocedimento com udp é disparada primeiro, e em seguida dispara a regra error (caso cumpra-se a condiçãode disparo).

Por esta razão recomendamos que sempre que se quer definir validações desse tipo, se utilize udp ao invésde call.

Page 21: 05 ordem execucaoregrase-formulas-cursogxxbr

Nas transações permite-se a programação dirigida por eventos, que é um estilo de programação naqual se define código que permanece ocioso, até que os eventos provocados pelo Usuário ou pelosistema, provoquem que o código definido seja executado.

Os eventos são ações reconhecidas por um objeto que podem acontecer ou não. A cada eventopodemos associar o código, que será executado somente caso o evento se produza.

O código que pode ser associado a um evento, é escrito de forma procedural; e quando o evento forproduzido, o código associado ao mesmo será executado seqüencialmente.

Page 22: 05 ordem execucaoregrase-formulas-cursogxxbr

Como em Web não se mantém um estado no servidor que permita saber o que está sendo executadono cliente, não é possível saber se está ingressando a primeira instancia de uma fatura, ou se é a n-ésima. Por esta razão, se disparará o evento Start cada vez que se envie ao servidor a informaçãoda instancia com a qual estiver trabalhando.

Enquanto que no evento Exit, se excuta por cada iteração, ao final da mesma.

O evento TrackContext é aplicado para obter interfaces de usuário sensíveis ao contexto.Programando este evento pode-se receber informação do contexto para depois tomar as decisõesnecessárias.

Page 23: 05 ordem execucaoregrase-formulas-cursogxxbr

O evento Start é um evento do sistema, ocorre automaticamente.

EXEMPLO:

Em uma transação nos interessa capturar a data e hora de entrada da mesma. Para isso no evento Start oatribuímos a uma variável de nome &entrada e tipo de dados DateTime, o resultado da função Now() quedevolve a data e hora atual:

Event Start&entrada = Now()

EndEvent

Se executa cada vez que se submeta o form da transação, ou seja, quando o usuário pressionar qualquerbotão do form.

Notas gerais:No evento Start fundamentalmente se trabalha com variáveis. Já a utilização dos atributos neste evento,seja para avaliá-los e/ou usá-los de algum modo exceto para atualizá-los, se deve considerar que osúnicos atributos que estão disponíveis são os que são recebidos por parâmetro na regra parm.Nenhum outro atributo terá valor neste evento, pois todavia não foi editado a instancia da transação.

Page 24: 05 ordem execucaoregrase-formulas-cursogxxbr

Como pode-se observar na sintaxe, deve-se dar um nome a um evento do usuário, após a palavra Event,que encontra-se entre aspas simples.

EXEMPLO:

Se deseja que na transação "Invoice", o usuário possa imprimir a fatura com a qual esteja trabalhando,pressionando F7 (isto somente é válido para Win):

Event ‘Print Invoice’ // evento definido na transação "Invoice"PrintInvoice.Call( InvoiceId )

EndEvent

Como associar um evento de usuário a um controle?

Além dos botões, também as imagens e os text blocks admitem a associação de evento de usuário. Pararealizar a associação se deve inserir o controle correspondente no form Web e depois nas propriedades docontrole, selecionar onde diz OnClickEvent um dos eventos existentes, ou se pode criar um novo.

Page 25: 05 ordem execucaoregrase-formulas-cursogxxbr

O evento After Trn das transações ocorre imediatamente depois da execução das regras com evento dedisparo AfterComplete. Em seguida, o código incluído neste evento, será executado depois que terminecada interação completa por meio da transação (assim que é gravado cada cabeçalho com suascorrespondentes linhas como registros físicos nas tabelas que corresponda e de se ter efetuado oCOMMIT).

Existem as seguintes alternativas para programar comportamentos que desejam ser executados no finalde cada interação completa por meio de uma transação:

1. Definir regras individuais com evento de disparo AfterComplete e deixar o evento After Trn sem código2. Definir todas as sentenças no evento After Trn com estilo procedural, e não definir regras com eventode disparo AfterComplete3. Definir as duas coisas: algumas regras com evento de disparo AfterComplete e código no evento AfterTrn

Como vemos explicando, primeiro são executadas as regras definidas com evento de disparoAfterComplete, e imediatamente após, executamos as regras com código definido no evento After Trn.

Um conceito que é muito importante ter claro é que tanto nas regras com evento de disparoAfterComplete como no evento After Trn, os valores dos atributos do primeiro nível da transação sãoconhecidos.

Ou seja, serão gravados fisicamente os registros correspondentes ao cabeçalho e as linhas de certainteração completa, inclusive se efetuou COMMIT, ainda temos disponíveis os valores dos atributos doprimeiro nível, podendo ser utilizados para passar por parâmetro em uma chamada, ou avaliar seu valor,ou usar de algum modo, exceto atualizá-los ¹.________________________________________________________________________________1 Existem dois motivos pelos quais não é possível atualizar atributos em regras com evento de disparoAfterComplete e After Trn. O primeiro motivo é que já foi realizado as gravações correspondentes eincluso o COMMIT já foi realizado, de modo que já é tarde para atribuir valores aos atributos. Além disso,relacionado ao evento After Trn, nos eventos não é permito realizar atribuições aos atributos.

Page 26: 05 ordem execucaoregrase-formulas-cursogxxbr

Não é permitido atribuir valores a atributos nos eventos.

Os valores dos atributos podem ser modificados nas transações:

· o usuário final fazendo, em tempo de execução, através do form (somente atributos das tabelas basesassociadas a transação, ou aqueles da estendida permitidos pela regra update)· mediante regras definidas pelo programador (a atributos das tabelas bases associadas a transação e suasestendidas)

Os eventos Start e Exit são sem tabela base. Com esta expressão nos referimos que nos eventos Start e Exitnão tem consulta ativa à base de dados (já que no evento Start ainda não foi feito a consulta e no evento Exitem Win já foi fechado o programa associado a transação e em Web a instancia está sendo fechada e já nãodispõe da consulta). Por este motivo é que não conhecemos valores de atributos nos eventos Start e Exit,exceto os recebidos por parâmetro.

Ao contrário, os eventos After Trn e de Usuário são com tabela base, quando os mesmos se executamtemos uma consulta feita. Então, em particular no evento After Trn, conhecemos os valores dos atributos doprimeiro nível (o segundo nível já foi inserido a essa altura e não tem possibilidade de posicionamento emalguma linha em particular); e no que diz respeito aos eventos de Usuário os atributos de todos os níveis 1

estão disponíveis.

É fundamental que fique claro, que assim que se disponha dos valores de certos atributos ou outrosdependendo do evento, os mesmos poderão ser utilizados para ser analisados e/ou passados por parâmetro aobjetos que se chamem, e/ou para alguma outra operação qualquer que não seja atribuir valor.

Concluindo, em nenhum evento (não somente das transações, mas em nenhum objeto GeneXus) permite-serealizar atribuições a atributos.

___________________________________________________________________________________________________________________________

1 Se num evento de usuário são referenciados atributos de um segundo nível ou outro nível subordinado,quando o evento de usuário for executado nos atributos daquela linha se tem um posicionamento; nomomento que o evento de usuário é executado serão considerados os valores dos atributos desta linha. Casoo usuário não se posicionou explicitamente em determinada linha, por default a linha que selecionada é aprimeira linha, assim serão estes os valores dos atributos considerados.