+ Start a Discussion
SeanCenoSeanCeno 

Batch Apex for Account Hierarchy

All,
I'm trying to refactor my trigger code to a batch. How can I execute my class to fire within the batch?

Class
public class Account_RollupProductInterest {
    protected final Account[] accountNewList;
    protected final Account[] accountOldList;
    Set<Id> acctIds = new Set<Id>();
    Decimal RXRsum = 0;
    Decimal A40Actsum = 0;
    Decimal DSTsum = 0;
    Decimal PPsum = 0;
    Decimal ITSum = 0;
    Decimal ActiveRepsSum = 0;
    Decimal NSTickets = 0;

    public Account_RollupProductInterest(Account[] accountOldList, Account[] accountNewList) {
        this.accountNewList = accountNewList;
        this.accountOldList = accountOldList;
    }

    public Account_RollupProductInterest(){
        new Account_RollupProductInterest().executeTableRollup();
    }

    //Update Numbers Table
    public void executeTableRollup(){
        for(Account a : accountNewList){
            if(a.ParentId != null){
                acctIds.add(a.ParentId);
            }
        }

        List<Account> updAcc = new List<Account>();
        List<Account> childAccts = new List<Account>([Select Id, Number_of_NS_RXR_Propects__c,
                                                        Number_of_40_Act_Fund_Prospects__c,
                                                        Number_of_DST_Prospects__c,
                                                        Number_of_Private_Placement_Prospects__c,
                                                        Number_of_Investor_Tickets__c,
                                                        Number_Of_Active_Reps__c,
                                                        Number_of_NorthStar_Tickets__c,
                                                   (Select Id, Number_of_NS_RXR_Propects__c,
                                                        Number_of_40_Act_Fund_Prospects__c,
                                                        Number_of_DST_Prospects__c,
                                                        Number_of_Private_Placement_Prospects__c,
                                                        Number_of_Investor_Tickets__c,
                                                        Number_Of_Active_Reps__c,
                                                        Number_of_NorthStar_Tickets__c
                                                From ChildAccounts)
                                                  From Account
                                                  Where Id in :acctIds]);
        for(Account acc : childAccts){
            for(Account child : acc.ChildAccounts){
                    RXRsum += (child.Number_of_NS_RXR_Propects__c != null ? RXRsum + child.Number_of_NS_RXR_Propects__c : 0);
                    acc.Number_of_NS_RXR_Propects__c = RXRsum;

                    A40Actsum += (child.Number_of_40_Act_Fund_Prospects__c != null ? A40Actsum + child.Number_of_40_Act_Fund_Prospects__c : 0);
                    acc.Number_of_40_Act_Fund_Prospects__c = A40Actsum;

                    DSTsum += (child.Number_of_DST_Prospects__c != null ? DSTsum + child.Number_of_DST_Prospects__c : 0);
                    acc.Number_of_DST_Prospects__c = DSTsum;

                    PPsum += (child.Number_of_Private_Placement_Prospects__c != null ? PPsum + child.Number_of_Private_Placement_Prospects__c : 0);
                    acc.Number_of_Private_Placement_Prospects__c = PPsum;

                    ITSum += (child.Number_of_Investor_Tickets__c != null ? ITSum + child.Number_of_Investor_Tickets__c : 0);
                    acc.Number_of_Investor_Tickets__c = ITSum;

                    ActiveRepsSum += (child.Number_Of_Active_Reps__c != null ? ActiveRepsSum + child.Number_Of_Active_Reps__c : 0);
                    acc.Number_Of_Active_Reps__c = ActiveRepsSum;

                    NSTickets += (child.Number_Of_NorthStar_Tickets__c != null ? NSTickets + child.Number_Of_NorthStar_Tickets__c : 0);
                    acc.Number_Of_NorthStar_Tickets__c = NSTickets;
            }
            
            updAcc.add(acc);
        }

        try {
            update updAcc;
        }
        Catch (Exception e) {
            System.debug('Exception : '+e.getMessage());
        }
    }
}

Batch:
Batch:
global class Contact_RollupProductInterestBatchable implements Database.Batchable<sObject> {
     global Database.QueryLocator start(Database.BatchableContext batchableContext){
	 	        return Database.getQueryLocator('Select Id From Account');

         /**String query = 'Select Id, Number_of_NS_RXR_Propects__c,'
                                 + 'Number_of_40_Act_Fund_Prospects__c,'
                                 + 'Number_of_DST_Prospects__c,'
                                 + 'Number_of_Private_Placement_Prospects__c,'
                                 + 'Number_of_Investor_Tickets__c,'
                                 + 'Number_Of_Active_Reps__c,'
                                 + 'Number_of_NorthStar_Tickets__c,'
                                 + '(Select Id, Number_of_NS_RXR_Propects__c,'
                                             + 'Number_of_40_Act_Fund_Prospects__c,'
                                             + 'Number_of_DST_Prospects__c,'
                                             + 'Number_of_Private_Placement_Prospects__c,'
                                             + 'Number_of_Investor_Tickets__c,'
                                             + 'Number_Of_Active_Reps__c,'
                                             + 'Number_of_NorthStar_Tickets__c'
                                             + 'From ChildAccounts)'
                                  + 'From Account';
         return Database.getQueryLocator(query);**/

    }

    global void execute(Database.BatchableContext batchableContext, Account[] accountNewList) {
        // Execute the rollup. It will auto-update the branch accounts once complete
        for(Account a : accountNewList){
        	a.Number_of_NS_RXR_Propects__c = a.ChildAccounts.Number_of_NS_RXR_Propects__c;
        	a.Number_of_40_Act_Fund_Prospects__c = a.ChildAccounts.Number_of_40_Act_Fund_Prospects__c;
        	a.Number_of_DST_Prospects__c = a.ChildAccounts.Number_of_DST_Prospects__c;
        	a.Number_of_Private_Placement_Prospects__c = a.ChildAccounts.Number_of_Private_Placement_Prospects__c;
        	a.Number_of_Investor_Tickets__c = a.ChildAccounts.Number_of_Investor_Tickets__c;
        	a.Number_Of_Active_Reps__c = a.ChildAccounts.Number_Of_Active_Reps__c;
        	a.Number_of_NorthStar_Tickets__c = a.ChildAccounts.Number_of_NorthStar_Tickets__c;
        }

        update accountNewList
    }

    global void finish(Database.BatchableContext batchableContext) {

    }
}

 
Best Answer chosen by SeanCeno
Asif Ali MAsif Ali M
Add the below constructor in your class.
public Account_RollupProductInterest(List<Account> accounts){
     this.accountNewList = accounts
}
Change your batch execute method to below.
global void execute(Database.BatchableContext batchableContext, Account[] accountNewList) { 
     Account_RollupProductInterest rollupObj = Account_RollupProductInterest( accountNewList )
     rollupObj.executeTableRollup();
    
}

Now you are all set to execute your batch.

Also note that the SOQL in executeTableRollup can easily hit  "SOQL Query Rows" Limit. With the deafult batch size 200 you can support the below numbers 200 Account with 500 child accounts( makes 50000 Query rows). If you hit the limit try to set the batch size to lower number.

 

All Answers

Asif Ali MAsif Ali M
Add the below constructor in your class.
public Account_RollupProductInterest(List<Account> accounts){
     this.accountNewList = accounts
}
Change your batch execute method to below.
global void execute(Database.BatchableContext batchableContext, Account[] accountNewList) { 
     Account_RollupProductInterest rollupObj = Account_RollupProductInterest( accountNewList )
     rollupObj.executeTableRollup();
    
}

Now you are all set to execute your batch.

Also note that the SOQL in executeTableRollup can easily hit  "SOQL Query Rows" Limit. With the deafult batch size 200 you can support the below numbers 200 Account with 500 child accounts( makes 50000 Query rows). If you hit the limit try to set the batch size to lower number.

 
This was selected as the best answer
SeanCenoSeanCeno
Thanks Asif. I'm getting the following error in the execute method:
 
Method does not exist or incorrect signature: Account_RollupProductInterest(List<Account>)
Any ideas? And also, in order to avoid the governor limits should I pull the SOQL out of the childAccts list? I tried to do it with an Aggregate Result, but I couldn't figure out how to use a subquery with it.
 
Asif Ali MAsif Ali M
Try the below line to initiate the object.
Account_RollupProductInterest rollupObj= Account_RollupProductInterest( (List <Account>) countNewList ):

Having small batchSize does not hurt. Only when you have above 50k child account for a single parent then you need to worry about.
SeanCenoSeanCeno
Yeah I got the same error. Tried this one too:
Account_RollupProductInterest rollupObj = Account_RollupProductInterest(new List<Account>(accountNewList));

 
Asif Ali MAsif Ali M
Sorry for that.actually I missed the "new" keyword in the object initialization 
SeanCenoSeanCeno
Ah. Right. Got it! Thanks!
global void execute(Database.BatchableContext batchableContext, Account[] accountNewList) {
        // Execute the rollup. It will auto-update the accounts once complete
        Account_RollupProductInterest rollupObj = new Account_RollupProductInterest(accountNewList);
        rollupObj.executeTableRollup();
    }