Desencadenadores de Apex masivos
Objetivos de aprendizaje
Después de completar esta unidad, podrá hacer lo siguiente:
- Escribir desencadenadores que funcionen en colecciones de sObjects.
- Escribir desencadenadores que realicen operaciones SOQL y DML eficientes.
Patrones de diseño de desencadenadores masivos
Los desencadenadores de Apex se han optimizado para funcionar de forma masiva. Se recomienda el uso de patrones de diseño masivos para procesar registros en desencadenadores. Mediante el uso de patrones de diseño masivos, mejora el desempeño de los desencadenadores, se consumen menos recursos de servidor y es menos probable que se superen los límites de la plataforma.
La ventaja de procesar el código de forma masiva es que este puede procesar un elevado número de registros de forma eficiente y ejecutarse dentro de los límites regulados en la Plataforma Lightning. Estos límites regulados se incluyen para garantizar que el código no controlado no monopolice los recursos de la plataforma de múltiples arrendatarios.
En las siguientes secciones se describen los métodos principales para procesar de forma masiva el código Apex en desencadenadores (realización de operaciones en todos los registros del desencadenador y aplicación simultánea de SOQL y DML a colecciones de sObjects en lugar de a sObjects individuales). Las mejores prácticas de procesamiento masivo de SOQL y DML se aplican a todo el código Apex, lo que incluye SOQL y DML en clases. Los ejemplos incluidos se basan en desencadenadores y se usa la variable de contexto Trigger.New
.
Realización de operaciones en conjuntos de registros
En primer lugar, vamos a examinar el concepto de diseño masivo más básico de los desencadenadores. Los desencadenadores procesados de forma masiva realizan operaciones en todos los sObjects en el contexto de los desencadenadores. Normalmente, los desencadenadores realizan operaciones en un registro si la acción que ha activado el desencadenador se origina en la interfaz de usuario. Sin embargo, si el origen de la acción ha sido DML masivo o la API, el desencadenador realiza operaciones en un conjunto de registros en lugar de en un solo registro. Por ejemplo, si importa muchos registros con la API, los desencadenadores realizan operaciones en todo el conjunto de registros. Por consiguiente, una práctica de programación adecuada es dar por supuesto siempre que el desencadenador realiza operaciones en una colección de registros de modo que funcione en todos los casos.
En el caso del siguiente desencadenador (MyTriggerNotBulk
), se da por supuesto que tan solo un registro ha activado el desencadenador. Este desencadenador no funciona en un conjunto de registros completo si se insertan varios registros en la misma transacción. En el siguiente ejemplo se muestra una versión procesada de forma masiva.
Este ejemplo (MyTriggerBulk
) es una versión modificada de MyTriggerNotBulk
. Se usa un bucle for
para iterar en todos los sObjects disponibles. Este bucle funciona si Trigger.New
contiene un solo sObject o muchos sObjects.
Aplicación de SOQL masivo
Las consultas SOQL pueden ser muy útiles. Puede recuperar registros relacionados y comprobar una combinación de múltiples condiciones en una sola consulta. Las funciones de SOQL permiten escribir menos código y realizar menos consultas a la base de datos. La reducción del número de consultas a la base de datos contribuye a evitar alcanzar los límites de consultas, los cuales se corresponden con 100 consultas SOQL para Apex sincrónico o 200 para Apex asíncrono.
En el siguiente desencadenador (SoqlTriggerNotBulk
) se muestra un patrón de consulta SOQL que se debe evitar. El ejemplo realiza una consulta SOQL dentro de un bucle for
para obtener las oportunidades relacionadas con cada cuenta, que se ejecuta una vez para cada cuenta sObject en Trigger.new
. Si tiene una larga lista de cuentas, una consulta SOQL en un bucle for
puede generar demasiadas consultas SOQL. En el siguiente ejemplo se muestra el método recomendado.
El ejemplo siguiente (SoqlTriggerBulk
) es una versión modificada de otra anterior y en él se muestra una mejor práctica para ejecutar consultas SOQL. La consulta SOQL hace la mayor parte del trabajo y se llama a ella una vez fuera del bucle principal.
- La consulta SOQL usa una consulta interna (
SELECT Id FROM Opportunities
) para obtener las oportunidades relacionadas de las cuentas. - La consulta SOQL se conecta a los registros del contexto del desencadenador mediante el uso de la cláusula
IN
y el enlace de la variableTrigger.new
en la cláusulaWHERE
(WHERE Id IN :Trigger.new
). Esta condiciónWHERE
filtra las cuentas para obtener solo los registros que activaron este desencadenador.
La combinación de las dos partes de los resultados de la consulta genera los registros correspondientes en una sola llamada (las cuentas de este desencadenador con las oportunidades relacionadas de cada cuenta).
Una vez obtenidos los registros y sus registros relacionados, el bucle for
itera en los registros de interés mediante el uso de la variable de recopilación (en este caso, acctsWithOpps
). La variable de colección contiene los resultados de la consulta SOQL. De este modo, el bucle for
itera solo en los registros en los que se van a realizar operaciones. Dado que ya se han obtenido los registros relacionados, no se requieren consultas adicionales en el bucle para obtener dichos registros.
De forma alternativa, si no necesita los registros principales de cuenta, puede recuperar solo las oportunidades relacionadas con las cuentas en el contexto de este desencadenador. Esta lista se especifica en la cláusula WHERE
mediante la coincidencia con el campo AccountId
de la oportunidad con el ID
de las cuentas de Trigger.New
: WHERE AccountId IN :Trigger.new
. Las oportunidades devueltas son para todas las cuentas en el contexto de este desencadenador y no para una cuenta específica. En el siguiente ejemplo se muestra la consulta usada para obtener todas las oportunidades relacionadas.
Puede reducir el tamaño del ejemplo anterior mediante la combinación de la consulta SOQL con el bucle for
en una sola declaración: bucle for
de SOQL. A continuación, se muestra otra versión de este desencadenador masivo mediante un bucle for
de SOQL.
Aplicación de DML masivo
Al hacer llamadas a DML en un desencadenador o una clase, realice estas llamadas a DML en una colección de sObjects siempre que sea posible. La aplicación de DML a cada sObject individualmente implica un uso ineficiente de los recursos. El tiempo de ejecución de Apex permite hasta 150 llamadas a DML en una sola transacción.
Este desencadenador (DmlTriggerNotBulk
) realiza una llamada de actualización en un bucle for
que itera en las oportunidades relacionadas. Si se cumplen determinadas condiciones, el desencadenador actualiza la descripción de las oportunidades. En este ejemplo, se llama una vez a la declaración update de forma ineficiente para cada oportunidad. Si una operación de actualización de cuentas masiva activa el desencadenador, puede haber muchas cuentas. Si cada cuenta tiene una o dos oportunidades, podemos terminar fácilmente con más de 150 oportunidades. El límite de la declaración DML es de 150 llamadas.
Este siguiente ejemplo (DmlTriggerBulk
) muestra cómo realizar declaraciones DML de forma masiva eficientes con una sola llamada a DML en una lista de oportunidades. En el ejemplo se agrega el sObject de oportunidad a una lista de oportunidades (oppsToUpdate
) en el bucle. A continuación, el desencadenador realiza la llamada a DML fuera del bucle en la lista una vez que se han agregado todas las oportunidades a la lista. Este patrón usa solo una llamada a DML con independencia del número de sObjects que se van a actualizar.
Proceso de patrón de diseño masivo: Ejemplo de obtención de registros relacionados
Vamos a aplicar los patrones de diseño que ya conoce mediante la escritura de un desencadenador que acceda a las oportunidades relacionadas de las cuentas. Modifique el ejemplo de desencadenador de la unidad anterior para el desencadenador AddRelatedRecord
. El desencadenador AddRelatedRecord
realiza operaciones de forma masiva, pero el de la unidad anterior no es tan eficiente como debería serlo ya que itera en todos los registros de sObject de Trigger.New
. En el siguiente ejemplo, se modifica tanto el código del desencadenador como la consulta SOQL para obtener solo los registros de interés y luego iterar sobre esos registros. Si no ha creado este desencadenador, no se preocupe, ya que puede hacerlo en esta sección.
Empecemos por revisar los requisitos del desencadenador AddRelatedRecord
. El desencadenador se activa una vez que se insertan o actualizan las cuentas. El desencadenador agrega una oportunidad predeterminada para cada cuenta que aún no tenga ninguna oportunidad.
En primer lugar, las cuentas recién insertadas nunca tienen una oportunidad predeterminada, así que definitivamente tenemos que agregar una. En el caso de las cuentas actualizadas, tenemos que determinar si tienen una oportunidad relacionada o no. Entonces, debemos separar cómo procesamos las inserciones y las actualizaciones mediante una instrucción switch
en la variable de contexto Trigger.operationType
. Luego, debemos realizar un seguimiento de las cuentas que necesitamos procesar con una variable toProcess
. Por ejemplo:
Para todas las inserciones de cuentas, simplemente asignamos las nuevas cuentas a la lista toProcess
:
Para las actualizaciones, debemos averiguar qué cuentas existentes en este desencadenador aún no tienen una oportunidad relacionada. Dado que este es un desencadenador posterior, podemos consultar los registros afectados en la base de datos. Aquí está la declaración SOQL, cuyos resultados asignamos a la lista toProcess
.
Ahora utilizamos un bucle for
para crear una iteración mediante la lista de cuentas toProcess
y agregar una oportunidad predeterminada relacionada a oppList
. Cuando terminemos, agregaremos la lista de oportunidades mediante la declaración DML insert
. Así es cómo se crea o actualiza el desencadenador completo.
- Si ya creó el desencadenador
AddRelatedRecord
en la unidad anterior, modifíquelo mediante la sustitución de su contenido por el siguiente desencadenador. En caso contrario, agregue el siguiente desencadenador mediante Developer Console e ingreseAddRelatedRecord
como nombre del desencadenador. - Para probar el desencadenador, cree una cuenta en la interfaz de usuario de Salesforce y asígnele el nombre
Lions & Cats
(Leones y gatos). - En la lista relacionada de oportunidades de la página de la cuenta, busque la oportunidad nueva
Lions & Cats
. El desencadenador ha agregado la oportunidad automáticamente.
Recursos