Skip to main content

Aplicar principios de la unidad de trabajo en Apex

Objetivos de aprendizaje

Después de completar esta unidad, podrá:

  • Describir la clase Unidad de trabajo y sus métodos.
  • Utilizar la clase fflib_SObjectUnitOfWork y su API en Apex.
Nota

Nota

¿Es su idioma de aprendizaje español (LATAM)? En esta insignia, las validaciones de los retos prácticos de Trailhead funcionan en inglés. Entre paréntesis se incluyen las traducciones a modo de referencia. En su instancia de Trailhead Playground, asegúrese de (1) cambiar la configuración local a los Estados Unidos, (2) cambiar el idioma a inglés, y (3) copiar y pegar solo los valores en inglés. Siga las instrucciones que figuran aquí.

Consulte la insignia Trailhead en su idioma para obtener más información sobre cómo aprovechar la experiencia de Trailhead en otros idiomas.

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 1:08:31, en caso de que desee rebobinar y mirar el comienzo del paso nuevamente).

Estiramiento de nuestras piernas con la Unidad de trabajo

Como este es un contenido avanzado, solo queda echar un vistazo a un escenario más complejo: la creación de una Oportunidad y todos los registros dependientes requeridos desde cero, cosa bastante sorprendente. El siguiente código de configuración de prueba muestra cómo se podría hacer esto sin la Unidad de trabajo. Más bien prolijo, ¿verdad?

List<Opportunity> opps = new List<Opportunity>();
List<List<Product2>> productsByOpp = new List<List<Product2>>();
List<List<PricebookEntry>> pricebookEntriesByOpp = new List<List<PricebookEntry>>();
List<List<OpportunityLineItem>> oppLinesByOpp = new List<List<OpportunityLineItem>>();
for(Integer o=0; o<10; o++) {
    Opportunity opp = new Opportunity();
    opp.Name = 'Opportunity ' + o;
    opp.StageName = 'Open';
    opp.CloseDate = System.today();
    opps.add(opp);
    List<Product2> products = new List<Product2>();
    List<PricebookEntry> pricebookEntries = new List<PricebookEntry>();
    List<OpportunityLineItem> oppLineItems = new List<OpportunityLineItem>();
    for(Integer i=0; i<o+1; i++) {
        Product2 product = new Product2();
        product.Name = opp.Name + ' :Product :' + i;
        products.add(product);
        PricebookEntry pbe = new PricebookEntry();
        pbe.UnitPrice = 10;
        pbe.IsActive = true;
        pbe.UseStandardPrice = false;
        pbe.Pricebook2Id = Test.getStandardPricebookId();
        pricebookEntries.add(pbe);
        OpportunityLineItem oppLineItem = new OpportunityLineItem();
        oppLineItem.Quantity = 1;
        oppLineItem.TotalPrice = 10;
        oppLineItems.add(oppLineItem);
    }
    productsByOpp.add(products);
    pricebookEntriesByOpp.add(pricebookEntries);
    oppLinesByOpp.add(oppLineItems);
}
// Insert Opportunities
insert opps;
// Insert Products
List<Product2> allProducts = new List<Product2>();
for(List<Product2> products :productsByOpp) {
    allProducts.addAll(products);
}
insert allProducts;
// Insert Pricebooks
Integer oppIdx = 0;
List<PricebookEntry> allPricebookEntries = new List<PricebookEntry>();
for(List<PriceBookEntry> pricebookEntries :pricebookEntriesByOpp) {
    List<Product2> products = productsByOpp[oppIdx++];
    Integer lineIdx = 0;
    for(PricebookEntry pricebookEntry :pricebookEntries) {
        pricebookEntry.Product2Id = products[lineIdx++].Id;
    }
    allPricebookEntries.addAll(pricebookEntries);
}
insert allPricebookEntries;
// Insert Opportunity Lines
oppIdx = 0;
List<OpportunityLineItem> allOppLineItems = new List<OpportunityLineItem>();
for(List<OpportunityLineItem> oppLines :oppLinesByOpp) {
    List<PricebookEntry> pricebookEntries = pricebookEntriesByOpp[oppIdx];
    Integer lineIdx = 0;
    for(OpportunityLineItem oppLine :oppLines) {
        oppLine.OpportunityId = opps[oppIdx].Id;
        oppLine.PricebookEntryId = pricebookEntries[lineIdx++].Id;
    }
    allOppLineItems.addAll(oppLines);
    oppIdx++;
}
insert allOppLineItems;

Ahora, rehagamos el código anterior utilizando el patrón Unidad de trabajo. Primero, comience creando una instancia Unidad de trabajo. Recuerde que los objetos pasados al constructor deben estar en orden de dependencia para el método commitWork para insertarlos en el orden correcto.

// Create a Unit Of Work
fflib_SObjectUnitOfWork uow = new fflib_SObjectUnitOfWork(
    new Schema.SObjectType[] {
        Product2.SObjectType,
        PricebookEntry.SObjectType,
        Opportunity.SObjectType,
        OpportunityLineItem.SObjectType
    }
);

En la unidad previa, el método de servicio applyDiscount utilizó el método registerDirty para registrar los registros Oportunidad y Partida de oportunidad para actualizar. El método registerNew inserta nuevos registros. Al insertar registros secundarios, este método también garantiza que se aplique el Id. principal correcto antes de insertar los registros secundarios. Puede ver esto en acción en la línea 22. Si tiene otras relaciones, también puede llamar el método registerRelationship (línea 21). ¿Ahora pongamos nuestra Unidad de trabajo en marcha! Nunca mejor dicho.

// Do some work!for(Integer o=0; o<10; o++) {
    Opportunity opp = new Opportunity();
    opp.Name = 'UoW Test Name ' + o;
    opp.StageName = 'Open';
    opp.CloseDate = System.today();
    uow.registerNew(opp);
    for(Integer i=0; i<o+1; i++) {
      Product2 product = new Product2();
      product.Name = opp.Name + ' :Product :' + i;
      uow.registerNew(product);
      PricebookEntry pbe = new PricebookEntry();
      pbe.UnitPrice = 10;
      pbe.IsActive = true;
      pbe.UseStandardPrice = false;
      pbe.Pricebook2Id = Test.getStandardPricebookId();
      uow.registerNew(pbe, PricebookEntry.Product2Id, product);
      OpportunityLineItem oppLineItem = new OpportunityLineItem();
      oppLineItem.Quantity = 1;
      oppLineItem.TotalPrice = 10;
      uow.registerRelationship(oppLineItem, OpportunityLineItem.PricebookEntryId, pbe);
      uow.registerNew(oppLineItem, OpportunityLineItem.OpportunityId, opp);
    }
}

Según la unidad anterior, estos métodos no realizan operaciones de base de datos. Para hacer eso, debe asignar el trabajo utilizando el método commitWork, que llama las declaraciones DML correctas con los registros que se registraron en el orden correcto de secundario y luego principal. Además, para relaciones, asigna el Id. principal en los registros secundarios, uniendo de forma efectiva su modelo de objeto cuando se inserta en la base de datos.

// Commit the work to the database!uow.commitWork();

Observe que el código es no solo más corto, también más fácil de leer en términos de lo que está ocurriendo sin todas esas fastidiosas listas alrededor. Aquí le mostramos más ejemplos de los métodos de registro que puede utilizar.

 // Inserts new Opportunity when committing
uow.registerNew(opp);
// Inserts new Opportunity Line Item and associates it with the given Opportunity record when committing
uow.registerNew(oppLineItem, OpportunityLineItem.OpportunityId, opp);
// Relates the given Opportunity Line Item to the given Price Book Entry when committing
uow.registerRelationship(oppLineItem, OpportunityLineItem.PricebookEntryId, pbe);

Resumen

En este módulo, obtuvo información acerca de las ventajas de visualizar su implementación de aplicación en capas que tienen sus propias consideraciones e inconvenientes. Como cualquier organismo, cada uno desempeña su parte en hacer que su aplicación sea sólida y duradera.

Realizó el primer paso en esa ruta aislando el corazón de su aplicación, su lógica de negocio. Puede detenerse aquí o puede continuar para aplicar preocupaciones de división al comportamiento de objeto (código de desencadenador) y consultando información que su aplicación necesita. Asegúrese de consultar el módulo Capas de dominios y selectores de los Patrones de negocio de Apex, que amplía el tema de las capas de dominios y selectores en la aplicación. Mientras tanto, ¡disfrute creando sus servicios!

Preparación para los retos

Para completar estos retos, necesita implementar algunas bibliotecas de código abierto. La clase fflib_SObjectUnitOfWork es parte de la biblioteca de código abierto Apex Common que es dependiente de la biblioteca de código abierto ApexMocks Framework. Deberá instalar ApexMocks primero y luego Apex Commons. Puede leer más acerca de ambas bibliotecas y sus acuerdos de licencia de código abierto respectivos en sus repositorios.

Para instalar las bibliotecas en su organización, simplemente utilice los botones "Implementar" a continuación.

Implemente la biblioteca de código abierto ApexMocks.

Implementar en Salesforce

Implemente la biblioteca de código abierto Apex Commons.

Implementar en Salesforce

Recursos

¡Siga aprendiendo gratis!
Regístrese para obtener una cuenta y continuar.
¿Qué hay para usted?
  • Consiga recomendaciones personalizadas para sus objetivos profesionales
  • Practique sus aptitudes con retos prácticos y pruebas
  • Siga y comparta su progreso con empleadores
  • Póngase en contacto para recibir asesoramiento y oportunidades laborales