4D v14.3

Triggers

Página Inicial

 
4D v14.3
Triggers

Triggers  


 

 

Um trigger é um método associado a uma tabela. É uma propriedade de uma tabela. Você não chama aos triggers; os triggers são chamados automaticamente pelo motor de 4D cada vez que manipular registros da tabela (adição, eliminação, modificação, carregar). Pode escrever triggers muito simples, e depois fazê-los mais sofisticados.

Os triggers podem evitar operações "ilegais" nos registros de seu banco. São uma ferramenta muito poderosa que permite controlar as operações em tabelas, além de evitar perdas de dados acidentalmente. Por exemplo, em um sistema de faturação, pode evitar que um usuário crie uma fatura sem especificar o cliente que deve ser faturado.

Por padrão, quando cria uma tabela no ambiente Desenho, a tabela não tem trigger.

Para utilizar um trigger para uma tabela, necessita:

  • Ativar o trigger e indicar a 4D quando chamá-lo.
  • Escrever o código para o trigger.

Ativar um trigger que não esteja escrito ou escrever um trigger sem ativá-lo não afeta as operações realizadas em uma tabela.

Para ativar um trigger, selecione as opções Triggers para a tabela na janela de propriedades da tabela:

Se essa opção for selecionada, o trigger será chamado cada vez que um registro da tabela seja modificado.
Isso acontece quando:

Nota: por razões de otimização, o trigger não é chamado quando o registro é guardado pelo usuário ou através do comando SAVE RECORD se nenhum campo da tabela tiver sido modificado no registro. Se deseja "forçar" o chamado do trigger neste caso, simplesmente pode atribuir um campo:
 [minhaTabela]meuCampo:=[minhaTabela]meuCampo

Se esta opção for selecionada, o trigger será chamado cada vez que um registro da tabela seja apagado, ou seja nas seguintes circunstâncias:

  • Quando apagar um registro (ambiente Desenho ou chamando DELETE RECORD, DELETE SELECTION, ou o comando DELETE).
  • Quando realizar operações que provocam a eliminação de um registro relacionado através das opções de controle de eliminação de uma relação.
  • Quando utilizar um plug-in que chama ao comando DELETE RECORD.

Nota: o comando APPLY TO SELECTION NÃO chama ao trigger.

Se esta opção for selecionada, o trigger será chamado todas as vezes  que um registro for criado na tabela, ou seja nas seguintes circunstâncias:

  • Quando adicionar um registro na entrada de dados (ambiente Desenho, comando ADD RECORD ou comando INSERT ).
  • Quando criar e guardar um registro com CREATE RECORD e SAVE RECORD. Note que o trigger é chamado no momento em que é chamado SAVE RECORD, e não quando é criado.
  • Quando importar registros (ambiente Desenho ou utilizando um comando de importação).
  • Quando chamar outros comandos que criam e/ou guardam novos registros (por exemplo, ARRAY TO SELECTION, SAVE RELATED ONE,, etc.).
  • Quando utilizar um plug-in que chama os comandos CREATE RECORD e SAVE RECORD

Para criar um trigger para uma tabela, utilize a janela de propriedades da tabela, clique no botão Editar ou pressione Alt (em Windows) ou Opção (Macintosh) e duplo clique na tabela na janela de estrutura. Para maior informação, consulte o manual de Desenho de 4D.

Um trigger pode ser chamado por um dos quatro eventos de banco descritos anteriormente. No trigger, pode detectar que evento está ocorrendo chamando a função Trigger event. Esta função retorna um valor numérico que indica o evento do banco.

Geralmente, um trigger é escrito com uma estrutura de tipo Case of sobre o resultado devolvido por Trigger event. Pode utilizar as constantes do tema LAST SUBRECORD:

  ` Trigger for [umaTabela]
 C_LONGINT($0)
 $0:=0 ` Assume que a petição será aceita
 Case of
    :(Database event=On Saving New Record Event)
  ` Realizar as ações apropriadas para guardar o novo registro criado
    :(Database event=On Saving Existing Record Event)
  ` Realizar as ações apropriadas para guardar um registro existente
    :(Database event=On Deleting Record Event)
  ` Realizar as ações apropriadas para apagar um registro
 End case

Um trigger tem dois propósitos:

  • Realizar ações sobre o registro imediatamente antes de que seja guardado ou apagado, ou imediatamente depois de ser carregado.
  • Aceitar ou recusar uma operação de banco de dados.

Cada vez que um registro for salvado (adicionado ou modificado) a uma tabela [Documentos], você deseja “marcar” o registro com os marcadores de criação e modificação. Pode escrever o seguinte trigger:` Trigger para tabla [Documentos]

 Case of
    :(Database event=On Saving New Record Event)
       [Documentos]Criação_marca:=Time stamp
       [Documentos]Modificação_marca:=Time stamp
    :(Database event=On Saving Existing Record Event)
       [Documentos]Modificação_marca:=Time stamp
 End case

Nota: a função Time stamp utilizada neste exemplo é um pequeno método de projeto que retorna o número de segundos transcorridos desde uma data escolhida arbitrariamente.

Quando este trigger tiver sido escrito e ativado, não importa de que maneira adiciona ou modifica um registro na tabela da tabela [Documentos] (entrada de dados, importação, método de projeto, plug-in 4D), os campos [Documentos]Criação_marca e [Documentos]Modificação_marca serão determinados automaticamente pelo trigger antes de que o registro seja escrito no disco.

Nota: ver o exemplo do comando GET DOCUMENT PROPERTIES para uma análise completa deste exemplo.

Para aceitar ou recusar uma operação do banco de dados, o trigger deve retornar um código de erro de trigger no resultado da função $0.

Imaginemos o caso de uma tabela [Empregados]. Durante a entrada de dados, você controla o campo [Empregados]Numero_Segurança_Social. Quando o usuário clicar no botão de validação, você verifica o campo utilizando o método de objeto do botão:

  ` Método de objeto bAccept
 If(Numero Valido([Empregados]Numero_Segurança_Social))
    ACCEPT
 Else
    BEEP
    ALERT("Introduza um número de segurança social e clique de novo em OK.")
 End if

Se o valor do campo for correto, aceita a entrada de dados; se o valor do campo não for correto, mostra um alerta e permanece em entrada de dados.

Se também criar registros para a tabela [Empregados] por programação, o seguinte código seria válido mas violaria a regra expressa no método de objeto criado anteriormente:

  ` Extração de um método de projeto
  ` ...
 CREATE RECORD([Empregados])
 [Empregados]Nome:="DOE"
 SAVE RECORD([Empregados]` <-- Violação da regra! O número de segurança social não tiver sido atribuido
  ` ...

Utilizando um trigger para a tabela [Empregados], pode implementar a regra [Empregados]Numero_Segurança_Social em todos os níveis do banco. O trigger seria assim:

  ` Trigger for [Empregados]
 $0:=0
 $dbEvent:=Database event
 Case of
    :(($dbEvent=On Saving New Record Event)|($dbEvent=On Saving Existing Record Event))If(Not(Numero Valido([Empregados]Numero_Segurança_Social)))
       $0:=-15050
    Else
  ` ...
    End if
  ` ...
End case

Quando este trigger estiver escrito e ativado, a linha SAVE RECORD ([Empregados]) gerará um erro de banco -15050, e o registro Não serão guardados.

Da mesma forma, se um plug-in 4D tentar guardar um registro em [Empregados] com um número de segurança social incorreto, o trigger gerará o mesmo erro e o registro não são guardadas.

O trigger garante que ninguém (usuário, desenvolvedor, plug-in, 4D Open client com 4D Server) possa violar a regra do número de segurança social, seja de forma deliberada ou acidental.

Note que mesmo que não tiver um trigger para uma tabela, o banco pode devolver erros quando tentar guardar ou apagar um registro. Por exemplo, se tentar salvar um registro com um valor duplicado em um campo indexado único, se retorna o erro -9998.

Os triggers retornam novos tipos de erros em 4D:

  • 4D administra os erros “normais”: índice único, controle de dados relacionais, etc.
  • Utilizando triggers, pode criar códigos de erros únicos para sua aplicação.
Importante: pode devolver o código de erro de sua escolha. Entretanto, NÃO utilize códigos de erro utilizados pelo motor de 4D. Recomendamos utilizar códigos de erro entre -32.000 e -15.000. Os erros superiores a -15.000 são reservados para o motor de 4D.

A nível do processo, você administra os erros trigger da mesma maneira que os erros de motor de banco de dados:
  • Pode permitir a 4D mostrar a caixa de diálogo de erro padrão, depois o método é interrompido.
  • Pode utilizar um método de gestão de erros instalado utilizando ON ERR CALL e recuperar o erro de maneira apropriada.
Notas:
  • Durante a entrada de dados, se um erro trigger for devolvido enquanto tenta confirmar ou apagar um registro, o erro é tratado como um erro de índice único. A caixa de diálogo de erro é mostrada, e permanece na entrada de dados. Mesmo se utilizar um banco no ambiente Desenho (não no ambiente Aplicação), você se beneficia do uso de triggers.
  • Quando um erro é gerado por um trigger no marco de um comando que atua sobre uma seleção de registros (como DELETE SELECTION), a execução do comando pára imediatamente, sem que a seleção tenha sido processada completamente. Este caso exige uma gestão apropriada por parte do desenvolvedor, baseada, por exemplo, na conservação temporária da seleção, o processamento e a eliminação do erro antes da execução do trigger, etc.
Mesmo quando um trigger não retornar um erro ($0:=0), isto não significa que uma operação do banco será exitosa, pode ocurrir uma violação de índice único. Se a operação for a atualização de um registro, o registro pode estar bloqueado, se pode produzir um erro de entrada/saida, etc. Estas verificações são realizadas depois da execução do trigger. Entretanto, desde o ponto de vista do nível superior do processo em execução, os erros devolvidos pelo motor da banco de dados ou por um trigger são da mesma natureza, um erro trigger é um erro do motor do banco de dados.

Os triggers funcionam ao nível do motor da banco de dados. Este ponto se resume no seguinte diagrama:



Os triggers são executados na máquina onde está o motor do banco de dados. Isso é evidente no caso de 4D versão single-user . Em 4D Server, os triggers são executados na máquina servidor (no processo ativo) e não na máquina  cliente.

Quando se chama um trigger, ele é executado dentro do contexto do processo que tenta a operação. Este processo, que invoca a execução do trigger,  se chama processo chamador.

Os elementos incluídos neste contexto são diferentes dependendo se o banco for executado com 4D em modo local ou com 4D Server:

  • Com 4D em modo local, o trigger funciona com as seleções atuais, registros atuais, estados de leitura/escrita das tabelas, operações de bloqueios de registros, etc., do processo chamador.
  • Com 4D Server, apenas o contexto de banco de dados do processo cliente chamador é conservado (bloqueio de registros, estados transacionados). 4D Server também garante que o registro atual da tabela do trigger está corretamente posicionado. Os outros elementos contextuais (seleções atuais por exemplo) são as do processo do trigger..
Tenha cuidado quando utilizar outros objetos do banco e da linguagem do ambiente 4D, porque um trigger pode ser executado em uma máquina diferente daquela do processo que o chamou - Este é o caso com 4D Server!
  • Variáveis interprocesso: um trigger tem acesso às variáveis interprocesso da máquina onde for executada. Com 4D Server, pode acessar a uma máquina diferente a do processo chamador.
  • Variáveis processo: cada trigger tem sua própria tabela de variáveis processo. Um trigger não tem acesso às variáveis processo do processo chamador.
  • Variáveis locais: pode utilizar as variáveis locais em um trigger. Seu alcance é a execução do trigger; são criados/eliminados a cada execução.
  • Semáforos: um trigger pode testar ou fixar semáforos globais e locais (na máquina onde for executada). Entretanto, um trigger deve ser executado rapidamente, de maneira que deve ter muito cuidado quando teste ou define semáforos dentro de triggers.
  • Conjuntos e seleções temporárias: se usar um conjunto ou uma seleção temporária em um trigger, você trabalha na máquina onde os triggers são executados. No modo cliente/servidor, conjuntos e seleções temporárias "processo" (cujos nomes não começam nem com um $  nem <>) que foram criadas na máquina cliente são visíveis em um trigger.
  • Interface do usuário: NÃO utilize elementos da interface de usuário em um trigger (nada de alertas, mensagens nem caixas de diálogo). Da mesma forma, deve limitar todo acompanhamento de triggers na janela do Depurador. Lembre que em Cliente/Servidor, os triggers são executados na máquina 4D Server. Uma mensagem de alerta na máquina servidor não ajuda ao usuário em uma máquina cliente. Deixe ao processo chamador administrar a interface do usuário.

As transações devem ser administradas ao nível do processo chamador. Não podem ser administrados ao nível do trigger. Se durante a execução do trigger, tiver que adicionar, modificar ou apagar vários registros (ver o estudo de caso a seguir), primeiro deve utilizar o comando In transaction desde o trigger para testar se o processo chamante está em transação atualmente. Se não for o caso, o trigger poderia ser encontrado com um registro bloqueado. Portanto, se o processo chamador não estiver em transação, nem comece as operações nos registros e retorna um erro em $0 para indicar ao processo chamador que a operação do banco de dados deve ser executada em uma transação. Por outro lado, se encontrar registros bloqueados, o processo chamante não poderá desfazer as ações do trigger.

Nota: Com o objetivo de otimizar o funcionamento combinado dos triggers e transações, 4D não chama triggers depois da execução de VALIDATE TRANSACTION. Isso evita que os triggers sejam executados duas vezes.

Dada a seguinte estrutura de exemplo:



Nota: as tabelas foram contraídas; tem mais campos dos que os mostrados aqui.

Suponhamos que o banco de dados “autoriza” a eliminação de uma fatura. Podemos examinar como seria tratada tal operação ao nível do trigger (porque também poderia realizar eliminações ao nível do processo).

Para conservar a integridade relacional dos dados, a eliminação de uma fatura exige as seguintes ações de parte do trigger de [Faturas]:

  • Diminuir o campo Vendas da tabela [Clientes], na quantidade da fatura.
  • Apagar todos os registros de [Linha_Fatura] relacionados com a fatura.
  • Isso também implica que o trigger de [Linha_Fatura] diminua o campo Quantidade vendida dos registros [Produtos] relacionados com a linha de fatura a ser eliminada.
  • Apagar todos os registros de [Pagos] relacionados com a fatura apagada.

Primeiro, o trigger de [Faturas] deve realizar estas ações apenas se o processo chamador estiver em transação, de maneira que seja possível desfazer em caso de encontrar um registro bloqueado.

Segundo, o trigger de [Linha_Fatura] está em cascata com o trigger de [Faturas]. O trigger [Linha_Fatura] é executado "dentro" da execução do trigger [Faturas], porque a eliminação dos elementos da lista é consecutiva a uma chamada a DELETE SELECTION desde o trigger de [Faturas].

Imagine que todas as tabelas neste exemplo tem triggers ativados para todos os eventos da banco de dados. A cascata de triggers será:
O trigger de [Faturas] é chamado porque o processo chamador apaga uma fatura
O trigger de [Clientes] é chamado porque o trigger de [Faturas] trigger atualiza o campo Vendas_Brutas
O trigger de [Linha_Fatura] é chamado porque o trigger [Faturas] apaga uma linha (repetida)
O trigger de [Produtos] é chamado porque o trigger de [Linha_Fatura] atualiza o campo Quantidade_Vendida
O trigger de [Pagamentos] é chamado porque o trigger de [Faturas] apaga um pagamento (repetido)

Nesta cascata, o trigger de [Faturas] é executado no nível 1, os triggers de [Clientes], [Linha_Fatura], e [Pagamentos] no nível 2 e o trigger de [Produtos] no nível 3.

De dentro dos triggers, é possível utilizar o comando Trigger level para detectar o nível no qual é executado um trigger. Além disso, pode utilizar o comando TRIGGER PROPERTIES para obter informação sobre os outros níveis.

Por exemplo,  um registro de [Produtos] é apagado a nível do processo, o trigger de [Produtos] será executado no nível 1, e não no nível 3.

Com Trigger level e TRIGGER PROPERTIES, pode identificar a causa de uma ação. Em nosso exemplo, uma fatura se apaga ao nível do processo. Se apagarmos um registro de [Clientes] ao nível do processo, o trigger de [Clientes] deve tentar apagar todas as faturas relacionadas com esse cliente. Isso significa que o trigger [Faturas] será chamado como no exemplo acima, mas por outra razão. Desde o trigger de [Faturas], pode detectar se foi executada no nível 1 ou 2. Se tiver sido  executado no nível 2, pode verificar se foi porque o registro de [Clientes] foi apagado. Se este for o caso, não precisa se preocupar com atualizar o campo Vendas_Brutas.

Quando manipular o evento de banco On Saving New Record Event, pode chamar ao comando Sequence number para manter um número de identificação único para os registros de uma tabela.

  ` Trigger for table [Faturas]
 Case of
    :(Database event=On Saving New Record Event)
  ` ...
       [Faturas]Numero_Identificação_Fatura:=Sequence number([Faturas])
  ` ...
 End case

 
PROPRIEDADES 

Produto: 4D
Tema: Triggers

 
VER TAMBÉM 

Métodos
Record number
Trigger event
Trigger level
TRIGGER PROPERTIES

 
ARTICLE USAGE

Manual de linguagem 4D ( 4D v14 R3)
Manual de linguagem 4D ( 4D v14 R2)
Manual de linguagem 4D ( 4D v13.5)
Manual de linguagem 4D ( 4D v14.3)
Manual de linguagem 4D ( 4D v14 R4)

Inherited from : Triggers ( 4D v11 SQL Release 6)