Skip to main content

Introdução aos acionadores do Apex

Objetivos de aprendizagem

Após concluir esta unidade, você estará apto a:
  • Escrever um acionador para um objeto do Salesforce.
  • Usar variáveis de contexto de acionadores.
  • Chamar um método de classe a partir de um acionador.
  • Usar o método addError() de sObject em um acionador para restringir operações de salvamento.
Nota

Nota

O desafio prático para esse emblema está traduzido para japonês, espanhol (América Latina) e português (Brasil). Para definir o idioma do seu Trailhead Playground, siga essas instruções. A tradução pode estar desatualizada. Se você não conseguir passar no desafio usando as instruções traduzidas, defina o idioma para inglês e a localidade para Estados Unidos. Em seguida, tente novamente.

Consulte o emblema Trailhead no seu idioma para saber mais sobre como aproveitar a experiência de Trailhead em outros idiomas.

Antes de começar

Os acionadores do Apex são úteis, divertidos e empolgantes. Embora este módulo ajude você a começar a usá-los, também faz referência a outros recursos do Salesforce para mostrar o poder dos acionadores do Apex. Para aproveitar ao máximo este módulo, recomendamos que você confira esses módulos primeiro:

Escrevendo acionadores do Apex

Os acionadores do Apex permitem que você execute ações personalizadas definidas antes ou depois de determinados eventos para registros no Salesforce, tais como inserções, atualizações ou exclusões. Assim como os sistemas de banco de dados suportam acionadores, o Apex fornece suporte a acionadores para o gerenciamento de registros.

Normalmente, os acionadores são usados para realizar operações baseadas em condições específicas, para modificar registros relacionados ou restringir determinadas operações. É possível usar acionadores para fazer tudo o que se pode fazer no Apex, inclusive executar SOQL e DML ou chamar métodos do Apex personalizados.

Use os acionadores para executar tarefas que não podem ser feitas usando as ferramentas de apontar e clicar na interface de usuário do Salesforce. Por exemplo, se estiver validando um valor de campo ou atualizando um campo em um registro, use as regras de validação e os fluxos. Use os acionadores do Apex se o desempenho e a escala forem importantes, se sua lógica for muito complexa para as ferramentas de apontar e clicar ou se estiver executando operações com uso intensivo de CPU.

Os acionadores podem ser definidos para objetos padrão de nível superior, como Conta ou Contato, objetos personalizados e alguns objetos filho padrão. Por padrão, os acionadores são ativados quando criados. O Salesforce dispara automaticamente os acionadores ativos quando os eventos de banco de dados especificados ocorrem.

Sintaxe do acionador

A sintaxe de uma definição de acionador é diferente da sintaxe de uma definição de classe. A definição de um acionador começa com a palavra-chave trigger. Depois, é seguida pelo nome do acionador, pelo objeto do Salesforce ao qual o acionador está associado e pelas condições sob as quais ele dispara. Um acionador tem a seguinte sintaxe:

trigger TriggerName on ObjectName (trigger_events) {
   code_block
}
Para executar um acionador antes ou depois de inserir, atualizar, excluir e cancelar exclusão de operações, especifique vários eventos de acionador em uma lista separada por vírgulas. Estes são os eventos que você pode especificar:
  • before insert (antes de inserir)
  • before update (antes de atualizar)
  • before delete (antes de excluir)
  • after insert (após inserir)
  • after update (após atualizar)
  • after delete (após excluir)
  • after undelete (após desfazer exclusão)

Exemplo de acionador

Este simples acionador dispara antes que uma conta seja inserida e escreve uma mensagem no registro de depuração.
  1. No Developer Console, clique em File (Arquivo) | New (Novo) | Apex Trigger (Acionador do Apex).
  2. Digite HelloWorldTrigger para o nome do acionador e, em seguida, selecione Conta para o sObject. Clique em Submit (Enviar).
  3. Substitua o código padrão pelo seguinte.

    trigger HelloWorldTrigger on Account (before insert) {
    	System.debug('Hello World!');
    }
  4. Para salvar, pressione Ctrl+S.
  5. Para testar o acionador, crie uma conta.
    1. Clique em Debug (Depurar) | Open Execute Anonymous Window (Abrir janela Executar anônimo).
    2. Na nova janela, adicione as informações a seguir e clique em Execute (Executar).

      Account a = new Account(Name='Test Trigger');
      insert a;
  6. No registro de depuração, localize a instrução Hello World!. O registro também mostra que o acionador foi executado.

Tipos de acionadores

Existem dois tipos de acionadores.

  • Pré-acionadores são usados para atualizar ou validar valores de registro antes que eles sejam salvos no banco de dados.
  • Pós-acionadores são usados para acessar os valores de campo que são definidos pelo sistema (tal como a Id de um registro ou o campo LastModifiedDate) e para realizar alterações em outros registros. Os registros que disparam o pós-acionador são de somente leitura.

Usando variáveis de contexto

Para acessar os registros que dispararam o acionador, use variáveis ​​de contexto. Por exemplo, Trigger.new contém todos os registros que foram inseridos nos acionadores de inserção ou atualização. Trigger.old fornece a versão antiga de sObjects antes de eles serem atualizados nos acionadores de atualização, ou uma lista de sObjects excluídos nos acionadores de exclusão. Os acionadores podem disparar quando um registro é inserido ou quando muitos registros são inseridos em grandes quantidades via API ou Apex. Portanto, variáveis de contexto, como Trigger.new, podem conter apenas um registro ou vários registros. Você pode iterar sobre Trigger.new para obter cada sObject individual.

Este exemplo é uma versão modificada do acionador de exemplo HelloWorldTrigger. Ele itera sobre cada conta em um loop for e atualiza o campo Description (Descrição) de cada uma.

trigger HelloWorldTrigger on Account (before insert) {
    for(Account a : Trigger.new) {
        a.Description = 'New description';
    }   
}
Nota

O sistema salva os registros que dispararam o pré-acionador, depois que o acionador termine a execução. É possível modificar os registros no acionador sem chamar explicitamente uma operação de inserção ou atualização de DML. Se você executar instruções DML nesses registros, receberá um erro.

Algumas outras variáveis ​​de contexto exibem um valor booleano para indicar se o acionador foi disparado devido a uma atualização ou a algum outro evento. Essas variáveis ​​são úteis quando um acionador combina diversos eventos. Por exemplo:

trigger ContextExampleTrigger on Account (before insert, after insert, after delete) {
    if (Trigger.isInsert) {
        if (Trigger.isBefore) {
            // Process before insert
        } else if (Trigger.isAfter) {
            // Process after insert
        }        
    }
    else if (Trigger.isDelete) {
        // Process after delete
    }
}

A tabela a seguir apresenta uma lista exaustiva de todas as variáveis ​​de contexto disponíveis para acionadores.

Variável Uso
isExecuting Retorna true se o contexto atual para o código do Apex for um acionador, não uma página do Visualforce, um serviço Web ou uma chamada de API executeanonymous().
isInsert Retorna true se este acionador tiver sido disparado devido a uma operação de inserção, a partir da interface de usuário do Salesforce, Apex ou API.
isUpdate Retorna true se este acionador tiver sido disparado devido a uma operação de atualização, a partir da interface de usuário do Salesforce, Apex ou API.
isDelete Retorna true se este acionador tiver sido disparado devido a uma operação de exclusão, a partir da interface de usuário do Salesforce, Apex ou API.
isBefore Retorna true se este acionador tiver sido disparado antes de qualquer registro ter sido salvo.
isAfter Retorna true se este acionador tiver sido disparado após todos os registros terem sido salvos.
isUndelete Retorna true se este acionador tiver sido disparado após um registro ter sido recuperado da Lixeira. Essa recuperação pode ocorrer depois de uma operação de cancelamento de exclusão a partir da interface de usuário do Salesforce, Apex ou API.
new Retorna uma lista das novas versões dos registros sObject.

Essa lista de sObjects está disponível apenas nos acionadores insert, update e undelete; os registros só podem ser modificados nos acionadores before.

newMap Um mapa de IDs para as novas versões dos registros sObject.

Esse mapa está disponível apenas nos acionadores before update, after insert, after update e after undelete.

old Retorna uma lista das versões antigas dos registros sObject.

Essa lista de sObjects está disponível apenas nos acionadores update e delete.

oldMap Um mapa de IDs para as versões antigas dos registros sObject.

Esse mapa está disponível apenas nos acionadores update e delete.

operationType Retorna um enum do tipo System.TriggerOperation correspondente à operação atual.

Alguns valores possíveis do enum System.TriggerOperation incluem: BEFORE_INSERT, BEFORE_UPDATE, BEFORE_DELETE, AFTER_INSERT, AFTER_UPDATE, AFTER_DELETE e AFTER_UNDELETE. Se você variar sua lógica de programação com base em vários tipos de acionador, pense em usar a instrução switch com permutações diferentes de estados únicos de enum de execução de acionador.

size O número total de registros em uma invocação do acionador – novos e antigos.

Chamando um Método de classe a partir de um Acionador

Você pode chamar métodos utilitários públicos a partir de um acionador. Chamar métodos de outras classes permite a reutilização de código, reduz o tamanho dos seus acionadores e melhora a manutenção do seu código do Apex. Também permite usar a programação orientada a objeto.

O exemplo de acionador a seguir mostra como chamar um método estático a partir de um acionador. Se o acionador tiver sido disparado devido a um evento de inserção, o exemplo chama o método estático sendMail() na classe EmailManager. Esse método utilitário envia um email ao destinatário especificado e contém o número de registros de contato inseridos.

  1. No Developer Console, clique em File (Arquivo) | New (Novo) | Apex Class (Classe do Apex).
  2. Insira EmailManager e clique em OK.
  3. Substitua o corpo da classe padrão pelo exemplo da classe EmailManager abaixo.
    public class EmailManager {
        // Public method
        public static void sendMail(String address, String subject, String body) {
            // Create an email message object
            Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
            String[] toAddresses = new String[] {address};
            mail.setToAddresses(toAddresses);
            mail.setSubject(subject);
            mail.setPlainTextBody(body);
            // Pass this email message to the built-in sendEmail method 
            // of the Messaging class
            Messaging.SendEmailResult[] results = Messaging.sendEmail(
                                      new Messaging.SingleEmailMessage[] { mail });
            // Call a helper method to inspect the returned results
            inspectResults(results);
        }
        // Helper method
        private static Boolean inspectResults(Messaging.SendEmailResult[] results) {
            Boolean sendResult = true;
            // sendEmail returns an array of result objects.
            // Iterate through the list to inspect results. 
            // In this class, the methods send only one email, 
            // so we should have only one result.
            for (Messaging.SendEmailResult res : results) {
                if (res.isSuccess()) {
                    System.debug('Email sent successfully');
                }
                else {
                    sendResult = false;
                    System.debug('The following errors occurred: ' + res.getErrors());                 
                }
            }
            return sendResult;
        }
    }
  4. No Developer Console, clique em File (Arquivo) | New (Novo) | Apex Trigger (Acionador do Apex).
  5. Digite ExampleTrigger para o nome do acionador e, em seguida, selecione Contact (Contato) para o sObject. Clique em Submit (Enviar).
  6. Substitua o código padrão pelo apresentado abaixo e, em seguida, modifique o texto do espaço reservado para o endereço de email em sendMail() referente ao seu endereço de email.
    trigger ExampleTrigger on Contact (after insert, after delete) {
        if (Trigger.isInsert) {
            Integer recordCount = Trigger.new.size();
            // Call a utility method from another class
            EmailManager.sendMail('Your email address', 'Trailhead Trigger Tutorial', 
                        recordCount + ' contact(s) were inserted.');
        }
        else if (Trigger.isDelete) {
            // Process after delete
        }
    }
  7. Para salvar, pressione Ctrl+S.
  8. Para testar o acionador, crie um contato.
    1. Clique em Debug (Depurar) | Open Execute Anonymous Window (Abrir janela Executar anônimo).
    2. Na nova janela, adicione as informações a seguir e clique em Execute (Executar).
      Contact c = new Contact(LastName='Test Contact');
      insert c;
  9. No registro de depuração, verifique se o acionador foi disparado. Perto do final do registro, localize a mensagem de depuração que foi escrita pelo método utilitário: DEBUG|Email sent successfully (DEPURAR|Email enviado com sucesso)
  10. Agora, verifique se você recebeu um email com o corpo de texto 1 contact(s) were inserted (1 contato foi inserido).

    Com seu novo acionador em vigor, você receberá um email sempre que adicionar um ou mais contatos!

Muitas vezes, os acionadores são usados para acessar e gerenciar registros relacionados aos registros no contexto do acionador – registros que dispararam o acionador.

Esse acionador adiciona uma oportunidade relacionada para cada conta nova ou atualizada caso nenhuma oportunidade já esteja associada à conta. O acionador primeiramente realiza uma consulta SOQL para obter todas as oportunidades filho das contas que o acionador disparou. Em seguida, o acionador itera sobre a lista de sObjects em Trigger.new para obter o sObject de cada conta. Se a conta não tem nenhum sObject de oportunidade relacionado, o loop for cria um. Se o acionador criou alguma nova oportunidade, a instrução final faz a inserção.

  1. Adicione o seguinte acionador usando o Developer Console (siga os passos do exemplo HelloWorldTrigger, mas use AddRelatedRecord para o nome do acionador).
    trigger AddRelatedRecord on Account(after insert, after update) {
        List<Opportunity> oppList = new List<Opportunity>();
        // Get the related opportunities for the accounts in this trigger
        Map<Id,Account> acctsWithOpps = new Map<Id,Account>(
            [SELECT Id,(SELECT Id FROM Opportunities) FROM Account WHERE Id IN :Trigger.new]);
        // Add an opportunity for each account if it doesn't already have one.
        // Iterate through each account.
        for(Account a : Trigger.new) {
            System.debug('acctsWithOpps.get(a.Id).Opportunities.size()=' + acctsWithOpps.get(a.Id).Opportunities.size());
            // Check if the account already has a related opportunity.
            if (acctsWithOpps.get(a.Id).Opportunities.size() == 0) {
                // If it doesn't, add a default opportunity
                oppList.add(new Opportunity(Name=a.Name + ' Opportunity',
                                           StageName='Prospecting',
                                           CloseDate=System.today().addMonths(1),
                                           AccountId=a.Id));
            }           
        }
        if (oppList.size() > 0) {
            insert oppList;
        }
    }
  2. Para testar o acionador, crie uma conta na interface de usuário do Salesforce e dê a ela o nome Apples & Oranges (Maçãs e Laranjas).
  3. Na lista relacionada de Oportunidades, na página da conta, localize a nova oportunidade. O acionador adicionou esta oportunidade automaticamente!
Nota

O acionador que você adicionou itera sobre todos os registros que fazem parte do contexto do acionador. O loop for itera sobre Trigger.new. No entanto, o loop neste acionador poderia ser mais eficiente. Realmente, não precisamos acessar cada conta no contexto deste acionador, mas apenas um subconjunto: o das contas sem oportunidades. A próxima unidade mostra como aumentar a eficiência deste acionador. Na unidade Padrões de design de acionadores em massa, aprenda a modificar a consulta SOQL para obter apenas contas sem oportunidades. Em seguida, aprenda a iterar somente sobre esses registros.

Usando exceções do acionador

Às vezes, você precisa adicionar restrições a determinadas operações de banco de dados, como impedir que registros sejam salvos quando determinadas condições forem atendidas. Para evitar que registros sejam salvos em um acionador, chame o método addError() sobre o sObject em questão. O método addError() lança um erro fatal dentro de um acionador. A mensagem de erro é exibida na interface de usuário e é registrada.

O acionador seguinte impede a exclusão de uma conta caso esta tenha oportunidades relacionadas. Por padrão, a exclusão de uma conta provoca uma exclusão em cascata de todos os seus registros relacionados. Este acionador impede a exclusão de oportunidades em cascata. Experimente usar este acionador! Se você já executou o exemplo anterior, sua organização tem uma conta chamada Apples & Oranges (Maçãs e laranjas) com uma oportunidade relacionada. Este exemplo usa essa conta de exemplo.

  1. Usando o Developer Console, adicione o acionador a seguir.
    trigger AccountDeletion on Account (before delete) {
        // Prevent the deletion of accounts if they have related opportunities.
        for (Account a : [SELECT Id FROM Account
                         WHERE Id IN (SELECT AccountId FROM Opportunity) AND
                         Id IN :Trigger.old]) {
            Trigger.oldMap.get(a.Id).addError(
                'Cannot delete account with related opportunities.');
        }
    }
  2. Na interface de usuário do Salesforce, acesse a página da conta Apples & Oranges (Maçãs e Laranjas) e clique em Delete (Excluir).
  3. No pop-up de confirmação, clique em OK.

    Localize o erro de validação com a mensagem de erro personalizada Cannot delete account with related opportunities.

  4. Desabilite o acionador AccountDeletion. Se deixar esse acionador ativo, você não poderá verificar seus desafios.
    1. Em Setup (Configuração), pesquise Apex Triggers (Acionadores do Apex).
    2. Na página Apex Triggers (Acionadores do Apex), clique em Edit (Editar), próximo ao acionador AccountDeletion.
    3. Desmarque a opção Is Active (Está ativo).
    4. Clique em Save (Salvar).
Nota
Chamar addError() em um acionador faz com que todo o conjunto de operações reverta, exceto quando a DML em massa é chamada com sucesso parcial.
  • Se uma chamada DML em massa na API da Lightning Platform gerou o acionador, o mecanismo de tempo de execução coloca os registros ruins de lado. O mecanismo de tempo de execução, então, tenta um salvamento parcial dos registros que não geraram erros.
  • Se uma instrução DML no Apex gerou o acionador, qualquer erro reverte toda a operação. No entanto, o mecanismo de tempo de execução ainda processa cada registro na operação para compilar uma lista abrangente de erros.

Acionadores e callouts

O Apex permite fazer chamadas e integrar seu código do Apex aos serviços web externos. As chamadas Apex aos serviços web externos são referidas como callouts. Por exemplo, você pode fazer um callout para um serviço de cotação de ações para receber as cotações mais recentes. Ao fazer um callout a partir de um acionador, o callout deve ser feito de forma assíncrona para que o processo do acionador não o impeça de trabalhar enquanto aguarda pela resposta do serviço externo. O callout assíncrono é feito em um processo de fundo, e a resposta é recebida quando o serviço externo retorna-o.

Para fazer um callout a partir de um acionador, chame um método de classe que execute de forma assíncrona. Esse método recebe o nome de método futuro e é anotado com @future(callout=true). Esta classe de exemplo contém o método futuro que faz o callout.

Nota

O exemplo usa o URL do ponto de extremidade hipotético apenas para fins ilustrativos. Este exemplo só pode ser executado se o ponto de extremidade for alterado para um URL válido e um site remoto for adicionado no Salesforce para o seu ponto de extremidade.

public class CalloutClass {
    @future(callout=true)
    public static void makeCallout() {
        HttpRequest request = new HttpRequest();
        // Set the endpoint URL.
        String endpoint = 'http://yourHost/yourService';
        request.setEndPoint(endpoint);
        // Set the HTTP verb to GET.
        request.setMethod('GET');
        // Send the HTTP request and get the response.
        HttpResponse response = new HTTP().send(request);
    }
}

Este exemplo mostra o acionador que chama o método na classe para fazer um callout de forma assíncrona.

trigger CalloutTrigger on Account (before insert, before update) {
    CalloutClass.makeCallout();
}

Esta seção apresenta apenas uma visão geral dos callouts e não tem como objetivo abordá-los detalhadamente. Para obter mais informações, consulte Como invocar callouts usando o Apex no Guia do desenvolvedor do Apex.

Continue a aprender de graça!
Inscreva-se em uma conta para continuar.
O que você ganha com isso?
  • Receba recomendações personalizadas para suas metas de carreira
  • Pratique suas habilidades com desafios práticos e testes
  • Monitore e compartilhe seu progresso com os empregadores
  • Conecte-se a orientação e oportunidades de carreira