0

Use Case

I Wanted to roll up opportunity count to the top level account.

for e.g account a=2 opps child of account b=4(+2 own opps) child of account c=6(+2 own opps).

For this i have created a roll up summary field on account to get counts of opportunity and a batch with size 1 which takes one Account at a time and processes that account to the top recursively to update the counts using rollup summary field.

Here is my batch.

global class UpdateAccountHierarchyR implements Database.Batchable<sObject>{

   global final String Query;   
   public Double tValue1;       

   //Static set to share processed ids among the all concurrent batches.
   //Unfortunately it is not working. 
   global static Set<Id> accIds=new Set<Id>();

   global UpdateAccountHierarchyR(String q){
      Query=q;
      //accIds=new Set<Id>();   
   }
   global Database.QueryLocator start(Database.BatchableContext BC){
      return Database.getQueryLocator(query);
   }
   global void execute(Database.BatchableContext BC, List<sObject> scope){     
     Account objAcc=(Account)scope[0];
     tValue1=0;//Counter to update opportunity counts to the top level account.
     //List<Account> lstAcc=new List<Account>();    
     List<Account> lstToUpdate=processNode(objAcc.id, new List<Account>());
     if(lstToUpdate.size()>0)
         update lstToUpdate;
   }
   public List<Account> processNode(string accId, List<Account> lstAcc){
       system.debug('**set**'+accIds.size());       
       List<Account> accs=new List<Account>([select id,ParentId,Opps_Count__c,Opps_CountR__c from Account where id=:accId]);
       Account objAcc=accs[0];       
       tCount1=tCount1+objAcc.Opps_CountR__c;//Roll up summary field for opportunities.
       objAcc.Opps_Count__c=tCount1;           
       if(!accIds.contains(objAcc.id)){
           lstAcc.add(objAcc);
           accIds.add(objAcc.id);
       }    
       if(Limits.getQueries()>199){
           system.debug('***:'+Limits.getQueries());           
           for(Integer i=0; i<10000; i++)
               Integer j=0;
           return lstAcc;
       }
       if(objAcc.ParentId!=null){
           processNode(objAcc.ParentId, lstAcc);
       }
       return lstAcc;
   }
   global void finish(Database.BatchableContext BC){   

   }
}

And i am calling this batch like this

UpdateAccountHierarchyR ua = new UpdateAccountHierarchyR('select id from Account');
id bpid=Database.executeBatch(ua, 1);

It is working perfect when i run with only one account in a scope but failing when i run with all accounts. Any workaround/suggestions would greatly appreciated.

Please Help thanks!

  • How many accounts do you have? It is really required to have batch for this? – Artur Kępczyński Feb 20 '14 at 8:02
  • @Birthus I am going to run this batch hourly, it can be any number of accounts. – SFIntegrator Feb 20 '14 at 8:42
  • 1
    Anyway - things like rollup values, I would consider moving this logic to trigger – Artur Kępczyński Feb 20 '14 at 9:18
  • Perhaps as part of your debug efforts, the code you have posted contains things like scope[0] which look blatantly wrong for batch sizes other than 1. I suggest you remove all the debugging junk and post a clean version of the code you think should work. – Keith C Feb 20 '14 at 17:33
  • the variable tCount1 is undefined – Pravin Feb 20 '14 at 19:07
1

You Should be doing this via a trigger, using a class to handle the records. You could then still use a batch class to update accounts every hours if you wish and reuse the class code, but to answer the comment in your code:

  1. You need to be using Database.Stateful
  2. change global static Set<Id> accIds=new Set<Id>(); to global Set<Id> accIds=new Set<Id>();

Declaring the property as Static does not carry through across batches, you need to use Database.Stateful

I have not reviewed the rest of your code but this will solve the immediate issue with the Set not being populated

  • side note - one has to also handle the use case of reparented Accounts that will require recalculation of the rollups (deducting from one hierarchy and adding to the new hierarchy). This means two triggers I think - one on Opportunity and one on Account. – cropredy Nov 29 '15 at 6:36
0

Please try having this variable inside execute method. Double tValue1;

Try with Database.Statefull

  • i tried this but doesn't seems to work. – SFIntegrator Feb 20 '14 at 7:24
0

I would highly recommend taking a look at this post: Avoiding SOQL limits in a recursive method

You should be able to build the hierarchy and manage static variables to roll up to the top.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.