Skip to main content

Aplicar princípios de Unit of Work no Apex

Objetivos de aprendizagem

Após concluir esta unidade, você estará apto a:

  • Descrever a classe Unit of Work e seus métodos.
  • Usar a classe fflib_SObjectUnitOfWork e sua API no Apex.
Nota

Nota

Deseja aprender em português (Brasil)? Nesse emblema, as validações dos desafios práticos do Trailhead funcionam em inglês. As traduções são fornecidas entre parênteses como referência No Trailhead Playground, (1) mude a localidade para Estados Unidos, (2) mude o idioma para inglês e (3) copie e cole apenas os valores em inglês. Siga as instruções aqui.

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

Acompanhar com o Trail Together

Deseja acompanhar um especialista enquanto trabalha nesta etapa? Veja este vídeo que faz parte da série Trail Together.

(Este clipe começa na marca dos 01:08:31 minutos, caso você queira retroceder e ver o início da etapa novamente.)

Como esticar as pernas com a Unit of Work

Já que se trata de conteúdo avançado, só faz sentido considerar um cenário mais complexo: criar uma oportunidade e todos os registros dependentes obrigatórios do zero. Isso é muito! O código de configuração de teste a seguir mostra como isso pode ser feito sem a Unit of Work. Bem detalhado, não é?

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;

Vamos refazer o código acima usando o padrão Unit of Work. Primeiro, comece criando uma instância de Unit of Work. Lembre-se de que os objetos transmitidos ao construtor devem estar na ordem de dependência para que o método commitWork possa inseri-los na ordem correta.

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

Na unidade anterior, o método de serviço applyDiscount usou o método registerDirty a fim de registrar os registros Oportunidade e Linha de oportunidade para atualização. O método registerNew insere novos registros. Ao inserir os registros filhos, esse método também faz com que a ID de pai correta seja aplicada antes de inserir os registros filhos. Você pode ver isso na prática na linha 22. Se você tem outros relacionamentos a criar, pode chamar o método registerRelationship (linha 21). Agora, vamos colocar nossa Unit of Work para funcionar! .

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

Conforme a unidade anterior, esses métodos não executam operações de bancos de dados. Para isso, você precisa confirmar o trabalho usando o método commitWork, que chama as instruções DML corretas com os registros que foram registrados na ordem correta de filho e, depois, pai. Além disso, no caso de relacionamentos, ele atribui a ID de pai aos registros filhos, costurando seu modelo de objeto conforme vai sendo inserido no banco de dados.

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

Observe que o código não só é mais curto, mas bem mais fácil de ler em termos de lógica, sem todas as listas em volta! Vejamos mais exemplos dos métodos register que você pode usar.

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

Resumo

Neste módulo, você aprendeu sobre os benefícios de exibir sua implementação de aplicativo em camadas que têm suas próprias considerações e questões. Assim como qualquer organismo, cada uma tem seu papel em tornar seu aplicativo mais sólido e duradouro.

Você deu o primeiro passo isolando o coração do seu aplicativo, a lógica de negócios. Você pode parar por aqui ou continuar a aplicar questões de separação ao comportamento do objeto (código acionador) e a consultar informações necessárias ao aplicativo. Não deixe de conferir o módulo Padrões corporativos do Apex: camadas de domínio e seletor, que continua com as camadas de aplicativo de domínio e seletor. Por enquanto, divirta-se criando seus serviços!

Preparação para os desafios

Para concluir os desafios, você precisará usar algumas bibliotecas de código aberto. A classe fflib_SObjectUnitOfWork é parte da biblioteca de código aberto Apex Common, que é dependente da biblioteca de código aberto ApexMocks Framework. Você precisará instalar o ApexMocks primeiro e, depois, o Apex Commons. Leia mais sobre essas bibliotecas e respectivos contratos de licença de código aberto em seus repositórios.

Para instalar as bibliotecas em sua organização, basta usar os botões “Implantar” abaixo.

Implantar a biblioteca de código aberto ApexMocks.

Implantar para Salesforce

Implantar a biblioteca de código aberto Apex Common.

Implantar para Salesforce

Recursos

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