2

I have a 1-to-many relationship using a lookup. I have a trigger that does a rollup on the parent object. So, anytime a child record is inserted, updated or deleted, the trigger fires and updates the master with the new rollup total. It works perfectly. However, there is a field on the parent object that if changed, needs to re-run the rollup of the child objects. What is the best approach to do this?

Also, I have another issue with a master-detail relationship, that the master record being deleted does not fire the child records delete via a cascade delete? How can I get the trigger to fire on the child object when the master is deleted?

Thanks for any help.

2 Answers 2

1

On the rollup question only...

This is a case where it is probably worth factoring out the code that does the rollup into a separate class. That then allows the triggers to be fairly simple:

trigger ParentTrigger on Parent__c (before ...) {
    if (change detected) {
        // Trigger objects will be persisted so just copy result
        for (Parent p : ChildRollup.calculateParents(Trigger.newMap)) {
            Trigger.newMap.get(p.Id).Sum__c = p.Sum__c;
        }
    }
}

trigger ParentTrigger on Parent__c (after ...) {
    if (change detected) {
        update ChildRollup.calculateParents(Trigger.newMap);
    }
}

trigger ChildTrigger on Child__c (...) {
    update ChildRollup.calculateParents(Trigger.newMap);
}

and sharing most of the code:

public class ChildRollup {
    public static Parent__c[] calculateParents(Map<Id, Parent__c> parents) {
        return calculateParents(parents.keySet());
    }
    public static Parent__c[] calculateParents(Map<Id, Child__c> children) {
        Set<Id> parentIds = new Set<Id>();
        for (Child__c c : children.values()) {
            parentIds.add(c.Parent__c);
        }
        return calculateParents(parentIds);
    }
    private static Parent__c[] calculateParents(Set<Id> parentIds) {
        Map<Id, Parent__c> parents = new Map<Id, Parent__c>();
        for (Id parentId : parentIds) {
            parents.put(parentId, new Parent__c(Id = parentId, Sum__c = 0.00));
        }
        for (AggregateResult ar : [
                select Parent__c p, sum(Value__c) s
                from Child__c
                where Parent_c in :parentIds
                group by Parent__c
                ]) {
            parents.get((Id) ar.get('p')).Sum__c += (Decimal) ar.get('s');
        }
        return parents.values();
    }
}
0

First off let me start by saying, please only ask one question at a time so we can best answer your question.

That being said, since no code is provided, I'm going to assume that the field being updated on the Parent object to re-run the rollup of the child objects, isn't a field that the child objects update. If it is, then you are going to run into issues with circular updating.

Otherwise this code would re-sum the child objects from the parent:

trigger MyTrigger on ParentObject__c (before update) {

  ParentObject__c[] parentList = new ParentObject__c[]{};

  for(ParentObject__c obj : Trigger.new) {
    if(obj.MyField__c != Trigger.oldMap.get(obj.Id).MyField__c)
      parentList.add(obj.Id);
  }

  Map<Id, Integer> childTotalMap = new Map<Id, Integer>();

  for(ChildObject__c cobj : [SELECT Id, ParentObject__c, FieldToSum__c FROM ChildObject__c WHERE ParentObject__c IN :parentList]) {
    if(!childTotalMap.containsKey(cobj.ParentObject__c)) {
      childTotalMap.put(cobj.ParentObject__c, cobj.FieldToSum__c);
    } else {
      Integer currentTotal = chiltTotalMap.get(cobj.Id);
      currentTotal += cobj.FieldToSum__c;
      childTotalMap.put(cobj.ParentObject__c, cobj.FieldToSum__c);
    }

  }

  for(ParentObject__c obj : Trigger.new) {
    if(childTotalMap.containsKey(obj.Id))
      obj.MyTotal__c = childTotalMap.get(obj.Id);
  }

}

Keep in mind I haven't tested this code, but should work for you with the little description you have provided.

To answer your second question, please see this question already asked as it should provide the information you seek.

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.