Quantcast
Channel: Thoughts From a Cloudy Mind
Viewing all articles
Browse latest Browse all 8

Refactoring and Improving…Fixing Roll-Up Summaries

$
0
0

After I posted this: http://wp.me/p1xleL-1w, Daniel Llewellyn (@Kenji776) commented that this could also be done using sub-queries. I recognized immediately that I he was right and my code was not as efficient as it could be. I finally found some time to refactor and what resulted is simpler and more efficient code.

The biggest change to the previous post is selecting the opportunities in a sub-select while querying the accounts:

select Id, Name, Total_Number_of_Opportunities__c,
Num_of_Won_Opportunities__c, Num_of_Closed_Opportunities__c,
(select Id, IsWon, IsClosed from Opportunities)
from Account where Id IN :accountIdSet

The main idea to take away from this is that we are selecting the accounts and ALL of the associated opportunities in a single select statement rather than selecting accounts, then selecting Opportunities. Also beyond reducing the number of SOQL to just one, we also eliminate the need to create a map of Account Ids to lists of opportunities.

I also want to point out that in the sub-select query we are querying “from Opportunities” not  “from Opportunity”. By querying Opportunities we are telling Salesforce.com to pull from just the opportunities tied to each account (and to group them by each account). For custom objects you will need to determine the child relationship name and then query that. For example, if you have a lookup field from the “Part” object to the “Car” object the Child Relationship Name (found on the lookup field detail) might be “Parts”. This means if you wanted to select all carss and the associated parts your query might look like this:

List<Car> carList = [select Id, Name, (select Id, Name from Parts__r) from Car];
for(Car c : carList){
  for(Part p : c.Parts__r){
    ...do stuff here...
  }
}

While this doesn’t greatly increase the  speed of a single opportunity update , imagine doing a bulk update all of your opportunities where you have an average of 25 opportunities per account. Since we no longer create a mapping of every account to its opportunities we greatly reduce the number of script statements need to get the job done.

So here is the updated code to perform roll-up summaries (And yes, I know this can be done using roll-up summary fields, but since I posted this example already, I am sticking with it.):

trigger updateAccountOpportunityCounts on Opportunity (after insert, after update, after delete, after undelete) {

    /*Create a Set to hold Acct Ids of opps in triger
      and a List to hold accts which will be updated*/
    Set<Id> accountIdSet = new Set<Id>();
    List<Account> accountUpdateList = new List<Account>();

    /*Create ths set of Account IDs.
      If this is a delete trigger, pull them the trigger.old,
      otherwise from trigger.new*/
    if(Trigger.isDelete)
        for(Opportunity o : trigger.old)
            accountIdSet.add(o.AccountId);
    else
        for(Opportunity o : trigger.new)
            accountIdSet.add(o.AccountId);

    /*Query for all of the accounts assoicated with the
      opportunities in the trigger using the above created set of Ids*/
    List<Account> acctOpptyList = [select Id, Name, Total_Number_of_Opportunities__c,
    			Num_of_Won_Opportunities__c, Num_of_Closed_Opportunities__c,
                (select Id, IsWon, IsClosed from Opportunities)
                from Account where Id IN :accountIdSet];

	/*loop through all of the accounts in the map and get
	  the counts for total number of opps,
	  count of closed and count of won opps.*/
    for(Account a : acctOpptyList){
        //initialize our counters
        Integer wonOpps = 0;
        Integer closedOpps = 0;

        //loop through the associated opportunities and count up the opportunities
        for(Opportunity o : a.Opportunities){
            if(o.IsClosed){
            	closedOpps++;
            	/*can't be won without being closed, reduce script statements
            	  by checking this inside IsClosed check*/
            	if(o.IsWon) wonOpps++;
            }
        }

        //set the counts
        a.Total_Number_of_Opportunities__c = a.Opportunities.size();
        a.Num_of_Won_Opportunities__c = wonOpps;
        a.Num_of_Closed_Opportunities__c = closedOpps;

        //add the account to the update list
        accountUpdateList.add(a);
    }

    //update all of the accounts if the list isn't empty
	if(!accountUpdateList.IsEmpty()) update accountUpdateList;
}


Viewing all articles
Browse latest Browse all 8

Trending Articles