Skip to main content
Build the future with Agentforce at TDX in San Francisco or on Salesforce+ on March 5–6. Register now.

Aprender sobre los principios de la unidad de trabajo

Objetivos de aprendizaje

Después de completar esta unidad, podrá:

  • Gestionar sus operaciones de DML de forma efectiva y evitar actualizaciones de base de datos parciales.
  • Comprender las funciones y las ventajas de la implementación de Apex del patrón.
  • Aplicar el patrón Unidad de trabajo al método de servicio applyDiscount desde la unidad anterior.

Siga el proceso con Trail Together

¿Desea seguir el proceso con un experto a medida que realiza este paso? Mire este video que forma parte de la serie Trail Together.

(Este video comienza en el minuto 54:05, en caso de que desee rebobinar y mirar el comienzo del paso nuevamente).

Principios de Unidad de trabajo

La Unidad de trabajo es un patrón de diseño que reduce códigos repetitivos al implementar gestión de transacciones y los gastos generales de codificación de la adhesión a la masificación de DML mediante el uso extenso de mapas y listas. No es un requisito para la implementación de una capa de servicio, pero puede ayudar. Le mostraremos un ejemplo de antes y después para explicar cómo funciona esto.

El patrón Unidad de trabajo utilizado en este módulo se basa en el patrón descrito por Martin Fowler: "Mantiene una lista de objetos afectados por una transacción de negocio y coordina la reescritura de cambios y la resolución de problemas de competitividad."

En Salesforce Platform, esto se traduce en el patrón que aborda los siguientes casos de uso:

  • Registro de actualizaciones, inserciones, y eliminaciones de registros para implementar un requisito de negocio específico.
  • Registro de relaciones de registros para facilitar la inserción de registros relacionados o secundarios con menos codificación.
  • Cuando se solicita redactar en la base de datos, masifica todos los registros capturados
  • Ajuste de DML realizado en SavePoint, liberando al desarrollador de la implementación de esto cada vez para cada método de servicio que se redacte

Implementación de un Método de servicio sin una Unidad de trabajo

Para comprender mejor qué ofrece el patrón Unidad de trabajo, primero veamos el código que hay que escribir sin usar la Unidad de trabajo en cada método de Servicio, a la vez que se cumple con las mejores prácticas de diseño analizadas anteriormente. Debemos redactar códigos para un requisito de negocio específico, pero también hacer que sirva como código reutilizado para implementar lo siguiente:

  • Optimización y masificación de DML: El código puede actualizar algunos de los registros Opportunity u OpportunityLineItem, o todos ellos, dependiendo del flujo de lógico. Crea y rellena dos listas para mantener solo la lectura de registros que requiere actualización.
  • Gestión de errores y gestión de transacciones: Según los principios de diseño de la capa de Servicio, debe asignar todos los cambios o ninguno si se produce un error, independientemente de si el interlocutor captura cualquier excepción que lanza. Recuerde que la plataforma revierte automáticamente solo si las excepciones no están gestionadas, lo que no es deseable desde una perspectiva de excepción de usuario. Es una buena práctica para el código de capa de Servicio gestionar un ámbito de transacción utilizando la instalación SavePoint y las semánticas try/catch.

En los siguientes ejemplos se usa un SavePoint para encapsular y abarcar las operaciones de base de datos en un método de Servicio, según las consideraciones de diseño. ¿Por qué? Imagine un escenario donde falla la segunda operación de DML. Sin un SavePoint en el método:

  • Si el agente que llama no maneja la excepción, se revertirá toda la transacción, incluida la primera operación de DML, ya que este es el comportamiento operativo de Apex predeterminado.
  • Si el agente que llama se ocupa de la excepción, sin permitir que se propague o sin restablecer un SavePoint, el tiempo de ejecución de Apex confirmará las actualizaciones en las líneas de oportunidad (primera declaración de DML), lo que causaría una actualización parcial de la base de datos.

Cuando no se usa el patrón Unidad de trabajo, se recomienda manejar múltiples operaciones de DML como se muestra en este ejemplo. Sin embargo, como verá en las siguientes secciones, la Unidad de trabajo puede ocuparse de esto.

public static void applyDiscounts(Set<Id> opportunityIds, Decimal discountPercentage) {
    // Validate parameters
    // ...
    // Query Opportunities and Lines
    // ...
    // Update Opportunities and Lines (if present)
    List<Opportunity> oppsToUpdate = new List<Opportunity>();
    List<OpportunityLineItem> oppLinesToUpdate = new List<OpportunityLineItem>();
    // Do some work...
    Decimal factor = 1 - (discountPercentage==null ? 0 : discountPercentage / 100);
    for(Opportunity opportunity : opportunities) {
        // Apply to Opportunity Amount
        if(opportunity.OpportunityLineItems!=null && opportunity.OpportunityLineItems.size()>0) {
            for(OpportunityLineItem oppLineItem : opportunity.OpportunityLineItems) {
                oppLineItem.UnitPrice = oppLineItem.UnitPrice * factor;
            oppLinesToUpdate.add(oppLineItem);
            }
        } else {
            opportunity.Amount = opportunity.Amount * factor;
          oppsToUpdate.add(opportunity);
        }
    }
    // Update the database
    SavePoint sp = Database.setSavePoint();
    try {
      update oppLinesToUpdate;
      update oppsToUpdate;
    } catch (Exception e) {
      // Rollback
      Database.rollback(sp);
      // Throw exception on to caller
      throw e;
    }
}

Implementación de Apex del patrón Unidad de trabajo

El resto de esta unidad hace referencia a una biblioteca de código abierto de Apex que contiene una implementación del patrón Unidad de trabajo de Martin Fowler. Se implementa a través de una clase única, fflib_SObjectUnitOfWork, por lo que continúe y abra esto en otra ficha. En la siguiente unidad, realizaremos prácticas con esta clase, pero por ahora, comprendamos un poco más acerca de sus métodos clave.

Esta clase expone métodos para permitir a una instancia de la clase fflib_SObjectUnitOfWork capturar registros que se deben crear, actualizar o eliminar cuando se ejecute el código de servicio a través de los métodos de registro. Además, el método commitWork encapsula el SavePoint y la convención try/catch.

La actualización de la base de datos con DML se produce únicamente cuando se llama el método commitWork. Por lo tanto, el código de servicio puede llamar los métodos de registro tantas veces y con la frecuencia que se necesite, incluso en bucles. Este enfoque permite al desarrollado centrarse en la lógica de negocio y no en códigos para gestionar múltiples listas y mapas.

Finalmente, como se muestra en el siguiente diagrama, el ámbito de Unidad de trabajo se determina por el inicio y la finalización de su código de método de servicio. Solo llame al commitWork una vez en el ámbito del método de servicio.

Para incluir la Unidad de trabajo en sus métodos de código de servicio, siga estos pasos.

  1. Inicialice una Unidad de trabajo única y utilícela para calcular el ámbito de todo el trabajo realizado por el método de servicio.
  2. Tenga los registros de lógica de capa de servicio con la Unidad de trabajo cuando se ejecuta.
  3. Llame el método commitWork de la Unidad de trabajo para masificar y ejecutar el DML.

El siguiente diagrama ilustra los siguientes pasos y aplica el ámbito de cada paso con respecto a la ejecución del código de método de servicio.

Cómo incluir Unidad de trabajo: cree una nueva instancia de unidad de trabajo, realice trabajos y registre cambios de registro y finalmente asigne una unidad de trabajo procesada de forma masiva a la base de datos.

Nota

Nota

Si está llamando entre servicios, pase la instancia de Unidad de trabajo exterior como un parámetro mediante la sobrecarga de métodos. No cree una nueva. Como la Unidad de trabajo está representando el ámbito transaccional del método de servicio, aspire a una sola instancia de Unidad de trabajo por llamada de método, como se muestra a continuación.

Para utilizar la clase Unidad de trabajo, debe crearla con una lista de los objetos con los que está interactuando su código. Los objetos deben estar en orden de dependencia para asegurarse de que registros principales y secundarios registrados están insertados por el método commitWork en el orden correcto. Exploraremos más acerca de la gestión de relaciones principal-secundario de fflib_SObjectUnitWork en la siguiente unidad.

fflib_SObjectUnitOfWork uow = new fflib_SObjectUnitOfWork(
        new List<SObjectType> { OpportunityLineItem.SObjectType, Opportunity.SObjectType  }
);

Implementación de un Método de servicio con la Unidad de trabajo

El siguiente ejemplo aplica al patrón Unidad de trabajo al servicio que creamos en la unidad anterior. El código que no cambia no se muestra. Observe que las listas quedan atrás y que el SavePoint no tiene un código reutilizado try/catch alrededor porque todo esto está gestionado por la clase fflib_SObjectUnitOfWork.

public static void applyDiscounts(Set<Id> opportunityIds, Decimal discountPercentage) {
    // Unit of Work
    fflib_SObjectUnitOfWork uow = new fflib_SObjectUnitOfWork(
        new List<SObjectType> { OpportunityLineItem.SObjectType, Opportunity.SObjectType  }
    );
    // Validate parameters
    // ...
    // Query Opportunities and Lines
    // ...
    // Update Opportunities and Lines (if present)
    // ...
    for(Opportunity opportunity : opportunities) {
        // Apply to Opportunity Amount
        if(opportunity.OpportunityLineItems!=null && opportunity.OpportunityLineItems.size()>0) {
            for(OpportunityLineItem oppLineItem : opportunity.OpportunityLineItems) {
                oppLineItem.UnitPrice = oppLineItem.UnitPrice * factor;
                uow.registerDirty(oppLineItem);
            }
        } else {
            opportunity.Amount = opportunity.Amount * factor;
            uow.registerDirty(opportunity);
        }
    }
    // Commit Unit of Work
    uow.commitWork();
}

La clase fflib_SObjectUnitOfWork agrega operaciones DML y las incluye en un SavePoint cuando se llama el método commitWork.

En códigos más complejos, con múltiples detalles y clases, puede elegir pasar SObjectUnitOfWork (o utilizar uno estático). El código llamado puede continuar para registrar sus propias actualizaciones de base de datos, sabiendo que el propietario de la Unidad de trabajo, en este caso, la capa de servicio, realiza una fase de asignación o reversión en su nombre.

Recursos

Comparta sus comentarios de Trailhead en la Ayuda de Salesforce.

Nos encantaría saber más sobre su experiencia con Trailhead. Ahora puede acceder al nuevo formulario de comentarios en cualquier momento en el sitio de Ayuda de Salesforce.

Más información Continuar a Compartir comentarios