Empiece a realizar un seguimiento de su progreso
Inicio de Trailhead
Inicio de Trailhead

Información general sobre desencadenadores de Apex

Objetivos de aprendizaje

Después de completar esta unidad, podrá:
  • Escribir un desencadenador para un objeto de Salesforce.
  • Usar variables de contexto de desencadenadores.
  • Llamar a un método de clase desde un desencadenador.
  • Usar el método addError() de sObject en un desencadenador para restringir las operaciones de guardado.

Escritura de desencadenadores de Apex

Los desencadenadores de Apex permiten realizar acciones personalizadas antes o después de eventos para registros en Salesforce, como inserciones, actualizaciones o eliminaciones. Del mismo modo que los sistemas de bases de datos admiten desencadenadores, Apex permite el uso de desencadenadores para la gestión de registros.

Normalmente, los desencadenadores se usan para realizar operaciones basadas en condiciones específicas, modificar registros relacionados o impedir determinadas operaciones. Puede usar desencadenadores para realizar cualquier operación admitida en Apex, lo que incluye la ejecución de SOQL y DML o la llamada a métodos Apex personalizados.

Use desencadenadores para realizar tareas que no se pueden realizar con herramientas interactivas (apuntar y hacer clic) en la interfaz de usuario de Salesforce. Por ejemplo, si va a validar un valor de campo o actualizar un campo de un registro, use reglas de validación y reglas de flujo de trabajo.

Se pueden definir desencadenadores para objetos estándar de nivel superior, como una cuenta o un contacto, objetos personalizados y determinados objetos secundarios estándar. Los desencadenadores se activan de forma predeterminada al crearlos. Salesforce activa automáticamente desencadenadores cuando se producen eventos de base de datos específicos.

Sintaxis de desencadenadores

La sintaxis de una definición de desencadenador es distinta de la sintaxis de una definición de clase. La definición de un desencadenador empieza por la palabra clave trigger. A continuación, le siguen el nombre del desencadenador, el objeto de Salesforce con el que está asociado el desencadenador y las condiciones en las que este se activa. Un desencadenador tiene la siguiente sintaxis:
trigger TriggerName on ObjectName (trigger_events) {
   code_block
}
Para ejecutar un desencadenador antes o después de operaciones de inserción, actualización, eliminación y recuperación, especifique varios eventos de desencadenador en una lista separada por comas. Los eventos que se pueden especificar son:
  • before insert
  • before update
  • before delete
  • after insert
  • after update
  • after delete
  • after undelete

Ejemplo

Este desencadenador sencillo se activa antes de insertar una cuenta y escribe un mensaje en el registro de depuración.
  1. En Developer Console, haga clic en File (Archivo) | New (Nuevo) | Apex Trigger (Desencadenador de Apex).
  2. Ingrese HelloWorldTrigger como nombre del desencadenador y, a continuación, seleccione la cuenta para sObject. Haga clic en Submit (Enviar).
  3. Sustituya el código predeterminado por lo siguiente:
    trigger HelloWorldTrigger on Account (before insert) {
    	System.debug('Hello World!');
    }
  4. Para guardar, pulse Ctrl+S.
  5. Para probar el desencadenador, cree una cuenta.
    1. Haga clic en Debug (Depurar) | Open Execute Anonymous Window (Abrir ventana de ejecución anónima).
    2. En la ventana nueva, agregue lo siguiente y, a continuación, haga clic en Execute (Ejecutar).
      Account a = new Account(Name='Test Trigger');
      insert a;
  6. En el registro de depuración, busque la declaración Hello World!. En el registro se muestra además que el desencadenador se ha ejecutado.

Tipos de desencadenadores

Hay dos tipos de desencadenadores.

  • Los desencadenadores previos se usan para actualizar o validar valores de registro antes de guardarlos en la base de datos.
  • Los desencadenadores posteriores se usan para acceder a los valores de campo establecidos por el sistema (por ejemplo, campo Id o LastModifiedDate de un registro) y aplicar cambios a otros registros. Los registros que activan el desencadenador posterior son de solo lectura.

Uso de variables de contexto

Para acceder a los registros que activan el desencadenador, use variables de contexto. Por ejemplo, Trigger.New contiene todos los registros insertados en desencadenadores de inserción o actualización. Trigger.Old proporciona la versión anterior de sObjects antes de actualizarlos en desencadenadores de actualización o una lista de sObjects eliminados en desencadenadores de eliminación. Los desencadenadores se pueden activar cuando se inserta un registro o cuando se insertan numerosos registros de forma masiva mediante la API o Apex. Por consiguiente, las variables de contexto, como Trigger.New, pueden contener solo un registro o varios registros. Puede iterar en Trigger.New para obtener cada sObject individual.

Este ejemplo es una versión modificada del desencadenador de ejemplo HelloWorldTrigger. Itera en cada cuenta mediante un bucle (for) y actualiza el campo de descripción en cada caso.

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

Nota

El sistema guarda los registros que han activado el desencadenador previo una vez que el desencadenador finaliza la ejecución. Puede modificar los registros en el desencadenador sin llamar de forma explícita a una operación de inserción o actualización de DML. Si realiza declaraciones DML en estos registros, obtiene un error.

Algunas otras variables de contexto devuelven un valor booleano para indicar si el desencadenador se ha activado debido a una actualización o a algún otro evento. Estas variables son de utilidad cuando un desencadenador combina varios eventos. Por ejemplo:

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
    }
}

Variables de contexto de desencadenadores

La tabla siguiente es una lista de todas las variables de contexto para desencadenadores.

Variable Uso
isExecuting Devuelve true si el contexto actual para el código Apex es un desencadenador, pero no una página de Visualforce, un servicio web o una llamada a API executeanonymous().
isInsert Devuelve true si este desencadenador se activó debido a una operación de inserción en la interfaz de usuario de Salesforce, Apex o la API.
isUpdate Devuelve true si este desencadenador se activó debido a una operación de actualización en la interfaz de usuario de Salesforce, Apex o la API.
isDelete Devuelve true si este desencadenador se activó debido a una operación de eliminación en la interfaz de usuario de Salesforce, Apex o la API.
isBefore Devuelve true si este desencadenador se ha activado antes de que se haya guardado cualquier registro.
isAfter Devuelve true si este desencadenador se ha activado después de que se hayan guardado todos los registros.
isUndelete Devuelve true si este desencadenador se ha activado después de recuperar un registro desde la papelera. Esta recuperación puede producirse después de una operación de recuperación desde la interfaz de usuario de Salesforce, Apex o la API.
new Devuelve una lista de versiones nuevas de registros de sObject.

Esta lista de sObject solamente está disponible en desencadenadores insert, update y undelete, y los registros únicamente se pueden modificar en desencadenadores before.

newMap Asignación de Id. a las versiones nuevas de los registros de sObject.

Esta asignación solo está disponible en los desencadenadores before update, after insert, after update y after undelete.

old Devuelve una lista de versiones anteriores de registros de sObject.

Esta lista de sObjects solo está disponible en los desencadenadores update y delete.

oldMap Asignación de Id. a las versiones anteriores de los registros de sObject.

Esta asignación solo está disponible en los desencadenadores update y delete.

operationType Devuelve una enumeración de tipo System.TriggerOperation correspondiente a la operación actual.

Los posibles valores de la enumeración System.TriggerOperation son: BEFORE_INSERT, BEFORE_UPDATE, BEFORE_DELETE,AFTER_INSERT, AFTER_UPDATE, AFTER_DELETE y AFTER_UNDELETE. Si varía su lógica de programación basándose en diferentes tipos de desencadenadores, considere el uso de la declaración switch con diferentes combinaciones de estados de enumeración de ejecución de desencadenador únicos.

size Número total de registros en una invocación de desencadenadores (tanto anteriores como nuevos).

Llamada a un método de clase desde un desencadenador

Puede llamar a métodos de utilidad públicos desde un desencadenador. La llamada a métodos de otras clases permite la reutilización de código, reduce el tamaño de los desencadenadores y mejora el mantenimiento del código Apex. Además, permite el uso de programación orientada a los objetos.

En el siguiente ejemplo de desencadenador se muestra cómo llamar a un método estático desde un desencadenador. Si el desencadenador se ha activado debido a un evento de inserción, en el ejemplo se llama al método estático sendMail() de la clase EmailManager. Este método de utilidad envía un email al destinatario especificado y contiene el número de registros de contacto insertados.

Nota

Nota

La clase EmailManager se incluye en el ejemplo de clase de la unidad Información general sobre Apex. Debe guardar la clase EmailManager en su organización y cambiar el método sendMail() a estático antes de guardar este desencadenador.

  1. En Developer Console, haga clic en File (Archivo) | New (Nuevo) | Apex Trigger (Desencadenador de Apex).
  2. Ingrese ExampleTrigger como nombre del desencadenador y, a continuación, seleccione Contact (Contacto) para el sObject. Haga clic en Submit (Enviar).
  3. Sustituya el código predeterminado por lo siguiente y, a continuación, modifique el texto de marcador de posición en sendMail() para su dirección 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
        }
    }
  4. Para guardar, pulse Ctrl+S.
  5. Para probar el desencadenador, cree un contacto.
    1. Haga clic en Debug (Depurar) | Open Execute Anonymous Window (Abrir ventana de ejecución anónima).
    2. En la ventana nueva, agregue lo siguiente y, a continuación, haga clic en Execute (Ejecutar).
      Contact c = new Contact(LastName='Test Contact');
      insert c;
  6. En el registro de depuración, compruebe si el desencadenador se ha activado. Al final del registro, busque el mensaje de depuración escrito mediante el método de utilidad: DEBUG|Email sent successfully.
  7. A continuación, compruebe si ha recibido un email con el texto de cuerpo 1 contact(s) were inserted.

    Con el nuevo desencadenador, recibirá un email cada vez que agregue uno o varios contactos.

Adición de registros relacionados

Los desencadenadores se suelen usar para gestionar y acceder a registros relacionados con otros registros en el contexto del desencadenador (registros que activan el desencadenador).

Este desencadenador agrega una oportunidad relacionada para cada cuenta nueva o actualizada si no hay ninguna oportunidad asociada a la cuenta. El desencadenador realiza primero una consulta SOQL para obtener todas las oportunidades secundarias de las cuentas en las que se ha activado el desencadenador. A continuación, el desencadenador itera en la lista de sObjects en Trigger.New para obtener el sObject de cada cuenta. Si la cuenta no tiene ningún sObject de oportunidad relacionado, el bucle (for) crea uno. Si el desencadenador ha creado oportunidades, la declaración final las inserta.

  1. Agregue el siguiente desencadenador mediante Developer Console (realice los pasos del ejemplo de HelloWorldTrigger, pero use AddRelatedRecord como nombre del desencadenador).
    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 probar el desencadenador, cree una cuenta en la interfaz de usuario de Salesforce y asígnele el nombre Apples & Oranges.
  3. En la lista relacionada de oportunidades de la página de la cuenta, busque la oportunidad nueva. El desencadenador ha agregado esta oportunidad automáticamente.

Más allá de lo básico

El desencadenador que ha agregado itera en todos los registros que forman parte del contexto del desencadenador (el bucle for itera en Trigger.New). No obstante, el bucle de este desencadenador podría ser más eficiente. En realidad no es necesario acceder a cada cuenta en el contexto de este desencadenador, sino solo a un subconjunto (cuentas sin oportunidades). En la siguiente unidad se describe cómo aumentar la eficiencia de este desencadenador. En la unidad Patrones de diseño de desencadenadores masivos, puede obtener información sobre cómo modificar la consulta SOQL para obtener solamente cuentas sin oportunidades. A continuación, puede aprender a iterar solamente en esos registros.

Uso de excepciones de desencadenadores

En ocasiones, es posible que necesite agregar restricciones para determinadas operaciones de base de datos, como impedir que los registros se guarden cuando se cumplen determinadas condiciones. Para evitar que los registros se guarden en un desencadenador, llame al método addError() del sObject en cuestión. El método addError() genera un error grave en el desencadenador. El mensaje de error se muestra en la interfaz de usuario y se registra.

El siguiente desencadenador impide la eliminación de una cuenta si esta tiene oportunidades relacionadas. De forma predeterminada, la eliminación de una cuenta provoca la eliminación en cascada de todos sus registros relacionados. Este desencadenador impide la eliminación en cascada de las oportunidades. Pruebe este desencadenador. Si ha ejecutado el ejemplo anterior, su organización tiene una cuenta llamada Apples & Oranges con una oportunidad relacionada. En este ejemplo se usa dicha cuenta.

  1. Use Developer Console para agregar el siguiente desencadenador.
    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. En la interfaz de usuario de Salesforce, navegue hasta la página de la cuenta Apples & Oranges y haga clic en Eliminar.
  3. En el mensaje emergente de confirmación, haga clic en Aceptar.

    Busque el error de validación con el mensaje de error personalizado Cannot delete account with related opportunities.

  4. Desactive el desencadenador AccountDeletion. Si deja este desencadenador activado, no podrá revisar los aspectos complejos.
    1. En Setup (Configuración), busque Apex Triggers.
    2. En la página Apex Triggers (Desencadenadores de Apex), haga clic en Edit (Modificar) junto al desencadenador AccountDeletion.
    3. Anule la selección de Is Active (Está activo).
    4. Haga clic en Save (Guardar).

Más allá de lo básico

La llamada a addError() en un desencadenador revierte todo el conjunto de operaciones, excepto si se llama a DML masivo con una validez parcial.

  • Si una declaración DML en Apex ha generado el desencadenador, cualquier error revierte toda la operación. No obstante, el motor en tiempo de ejecución sigue procesando cada registro de la operación para compilar una lista de errores exhaustiva.
  • Si una llamada a DML masivo en la API de Plataforma Lightning ha generado el desencadenador, el motor en tiempo de ejecución prescinde de los registros incorrectos. A continuación, el motor en tiempo de ejecución intenta el almacenamiento parcial de los registros que no han generado errores.

Desencadenadores y llamadas

Apex permite hacer llamadas e integrar el código Apex con servicios web externos. Estos contactos de Apex con servicios web externos se denominan llamadas. Por ejemplo, puede hacer una llamada a un servicio de cotización para conocer las últimas cotizaciones. Al hacer una llamada desde un desencadenador, dicha llamada se debe hacer de forma asíncrona para que el proceso del desencadenador no le impida trabajar mientras espera la respuesta del servicio externo. La llamada asíncrona se realiza mediante un proceso en segundo plano y la respuesta se recibe cuando el servicio externo la devuelve.

Para hacer una llamada desde un desencadenador, llame a un método de clase que se ejecute de forma asíncrona. Este método se llama método futuro y se anota con @future(callout=true). Esta clase de ejemplo contiene el método futuro que hace la llamada.

Nota

Nota

En el ejemplo se una dirección URL de extremo hipotética con fines ilustrativos. No puede ejecutar este ejemplo a menos que cambie el extremo a una URL válida y agregue un sitio remoto en Salesforce para su extremo.

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);
    }
}

En este ejemplo se muestra el desencadenador que llama al método en la clase para hacer una llamada asíncrona.

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

Esta sección es solo una descripción general de las llamadas y el objetivo no es proporcionar información detallada. Para obtener más información, consulte Invocación de llamadas utilizando Apex en la Guía del desarrollador de Apex.

Recursos