+ Start a Discussion
Tom Guo 19Tom Guo 19 

Need Help Bulkifying Apex Code

I'm looking for other/ better ways to implent the code below. 

Use Case: 

I have a custom Project__c object which gets created when an Opportunity becomes Closed Won. If the Opportunity has certain Opportunity Products which have the Hours_Contribute_to_Project__c checkbox set to true, when the Project is created, it will tally all the quantities of these respective Opportunity Products to see how many hours were purchased and input the value within the respective Project record. Project and Opportunity have a lookup relationship. 

Code: 
 The following code works but I'm wondering how to make it more efficient without the SOQL query in the FOR loop. Thanks!
public static void CalculateHoursPurchased(List<Project__c> projectList){
    
    for(Project__c a: projectList){
        
        AggregateResult hoursPurchased = [SELECT SUM(Quantity)
                                          FROM OpportunityLineItem
                                          WHERE Hours_Contribute_to_Project__c = TRUE AND Opportunity.Id = :a.Opportunity__c];
        
        Decimal b = (decimal)hoursPurchased.get('expr0');
        a.Hours_Purchased__c = b;
        
    }
    
}

 
Best Answer chosen by Tom Guo 19
Alain CabonAlain Cabon
You can group by OpportunityId.
 
public static void CalculateHoursPurchased(List<Project__c> projectList){
    
     Map<String,String> mp = new Map<String,String> ();
     for (Project__c p:projectList) {
          mp.put(p.Opportunity__c,p.Id);
     }

     AggregateResult hoursPurchasedResults = [SELECT OpportunityId, SUM(Quantity) Sum FROM OpportunityLineItem WHERE Hours_Contribute_to_Project__c = TRUE AND OpportunityId in :mp.keySet() GROUP BY OpportunityId];

    List<Project__c> upd = new List<Project__c>();

    for (AggregateResult ar : hoursPurchasedResults )
        
        Decimal b = (Decimal)ar.get('Sum');
        Project__c np = new Project__c(Id = mp.get(ar.get('OpportunityId')), Hours_Purchased__c = b);

        upd.add(np);
        
    }
    if (upd.size() > 0) {
        update upd;
    }   
}

 

All Answers

David Zhu 🔥David Zhu 🔥
You may use the following snipt for reference, fix typos and restyle.

public static void CalculateHoursPurchased(List<Project__c> projectList){
    List<Id> oppIds = new List<Id>();

   for (Project__c p : projectList){
oppIds.add(p.opporutnity__c);
 }

List<OpportunityLineItem> oppLineItems = [Select Opportunity,Quantity from OpportunityLineItem where Opportunity in :oppIds];
Map<Id,decimal> oppQuantityMap = new Map<Id,decimal>();
for (OpportunityLineItem opplineitem : oppLineItems) {
     deciaml quantity = 0;
     if (oppQuantityMap.ContainsKey(opplineitem.Opportunity){
        quantity =  oppQuantity.get(opplineitem.Opportunity);
      }

      quantity += opplineitem.quantity;
     
     oppQuantityMap.put(opplineitem.opportunity,quantity);
}

    for(Project__c a: projectList){
        a.Hours_Purchased__c = oppQuantityMap.get(a.Opportunity);        
    }
    
}
Alain CabonAlain Cabon
You can group by OpportunityId.
 
public static void CalculateHoursPurchased(List<Project__c> projectList){
    
     Map<String,String> mp = new Map<String,String> ();
     for (Project__c p:projectList) {
          mp.put(p.Opportunity__c,p.Id);
     }

     AggregateResult hoursPurchasedResults = [SELECT OpportunityId, SUM(Quantity) Sum FROM OpportunityLineItem WHERE Hours_Contribute_to_Project__c = TRUE AND OpportunityId in :mp.keySet() GROUP BY OpportunityId];

    List<Project__c> upd = new List<Project__c>();

    for (AggregateResult ar : hoursPurchasedResults )
        
        Decimal b = (Decimal)ar.get('Sum');
        Project__c np = new Project__c(Id = mp.get(ar.get('OpportunityId')), Hours_Purchased__c = b);

        upd.add(np);
        
    }
    if (upd.size() > 0) {
        update upd;
    }   
}

 
This was selected as the best answer