0

So in attempting to write a trigger to roll-up numerical values via a lookup field, I appeared to have made a mistake in the code so it updates enough records to throw an error. I thought the way it's written would only update the Account after insert of a Time_Item__c.

Class:

    public class LookupCalculation{

    public enum Method {COUNT, SUM, MIN, MAX, AVG} 

    private string sobjectParent, 
                   relationName, 
                   formulaParent, 
                   sobjectChild, 
                   parentfield, 
                   fieldChild;

    public LookupCalculation(string mysobjectParent, string myrelationName, string myformulaParent,
                             string mysobjectChild, string myparentfield, string myfieldChild){
        sobjectParent = mysobjectParent;
        relationName = myrelationName;
        formulaParent = myformulaParent;
        sobjectChild = mysobjectChild;
        parentfield = myparentfield;
        fieldChild = myfieldChild;
    }

    public void Calculate(Method calculation, List<sobject> childList){
        set<Id> parentIdSet = new set<Id>();
        for(sobject sobj : childList)
            parentIdSet.add((Id) sobj.get(parentfield));
        string soqlParent = 'select id, (select ' + fieldChild + ' from ' + relationName + ') from ' + sobjectParent + '';
        List<sobject> parentList = Database.query(soqlParent);

        for(sobject parent : parentList){
            List<sobject> children = parent.getSObjects(relationName);
            if(children == null)
                children = new List<sobject>();
            Decimal counter = (mustSum(calculation))? 0 : null;
            //if(calculation == Method.COUNT)
              //  counter = children.size();
            for(sobject child : children){
                Decimal value = (Decimal) child.get(fieldChild);
                if(mustSum(calculation) && value != null)
                    counter += value;
                //else if(calculation == Method.MIN && (counter == null || value < counter))
                  //  counter = value;
                //else if(calculation == Method.MAX && (counter == null || value > counter))
                  //  counter = value;
            }
           // if(calculation == Method.AVG && children.size() > 0)
             //   counter = counter / children.size();
            parent.put(formulaParent, counter);
        }
        update parentList;
    }

    private boolean mustSum(Method calculation){
        return (calculation == Method.SUM || calculation == Method.AVG);
    }

}

Trigger:

    trigger TimeItemRollupAcct on Time_Item__c (after insert,after update,after delete,after undelete) {

    /*******************TO BE CUSTOMIZED*********************/
    string mysobjectParent = 'Account',      // Parent sobject API Name
           myrelationName = 'Time_Items__r', // Api name of the relation between parent and child (ends with __r)
           myformulaParent = 'ApexHours__c',        // Api name of the number field that will contain the calculation
           mysobjectChild = 'Time_Item__c',  // Child sobject API Name
           myparentfield = 'AccountTime__c', // Api name of the lookup field on chield object
           myfieldChild = 'Hours__c';          // Api name of the child field to roll up

    LookupCalculation.Method method = LookupCalculation.Method.SUM; //Selected method: could be COUNT, SUM, MIN, MAX, AVG
    /*******************************************************/

    LookupCalculation calculation = new LookupCalculation(mysobjectParent, myrelationName, myformulaParent,
                                                          mysobjectChild, myparentfield, myfieldChild);
    List<sobject> objList = new List<sobject>((List<sobject>) Trigger.new);

    if(Trigger.isDelete)
        objList = Trigger.old;
    if(Trigger.isUpdate)
        objList.addAll((List<sobject>) Trigger.old);
    calculation.calculate(method, objList);
}
  • Why aren't you using parentIdSet when doing the SOQL query? Surely you should be doing a where Id in :parentIdSet to limit the amount of records that is returned. Without this where condition your code is selecting all Accounts in the org no matter how many were updated in the trigger. – BarCotter Jan 12 '15 at 11:33
  • Yikes, just goes to show you can't trust every bit of code you find. Your fix did the trick. – Ian Bury Jan 12 '15 at 14:06
  • Glad it helped. I've converted my comment into an answer. – BarCotter Jan 12 '15 at 15:53
3

Your query should only be returning accounts that were inserted/updated in the trigger. Your current code is selecting all accounts.

You need to update your query as shown below:

String soqlParent = 'select id, (select ' + fieldChild + ' from ' + relationName
          + ') from ' + sobjectParent + ' where id in :parentIdSet';

Without this where condition your code is selecting all Accounts in the org no matter how many were updated in the trigger.

-1

By looking at your code I am not 100% sure where your issue is by I would say most probably it is because it is falling into a infinite loop of trigger calls, which I guess would be time item trigger > Account trigger > something else > time item trigger. Since your current code has no mechanism preventing that.

I would suggest adding a static variable recording whether you are inside a time item trigger or not, if that equals to true, you don't want to execute your time item trigger code.

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.