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);
}
parentIdSet
when doing the SOQL query? Surely you should be doing awhere Id in :parentIdSet
to limit the amount of records that is returned. Without thiswhere
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