1

Below apex class and apex trigger must be able to update child records every time its parent record is updated. Apex class holds the logic itself, while apex trigger calls the apex class. There is no error when I save it, but child records are not updated.

Apex Class:

public class UpdateDetailClass {

    public static void UpdateDetailMethod(List<Master__c> masterList) {

        Set<Id> masterIds = new Set<Id>();

        for(Master__c master : masterList) {
            masterIds.add(master.Id);  
        }

        List<Detail__c> detailList = new List<Detail__c>([SELECT Id, Master__c, Master__r.isSelected__c, Type__c FROM Detail__c WHERE Master__c IN: masterIds]);

        List<Detail__c> detailToUpdate = new List<Detail__c>();

        for(Master__c master : masterList) {

            for(Detail__c d : detailList) {
                if(master.Id != null) {
                    if(master.isSelected__c == true) {
                        d.Master__c = master.Id;
                        d.Type__c = master.Type__c;
                        detailToUpdate.add(d);
                    }    
                }    
            }

        }

        update detailToUpdate;     

    } 

}

Apex Trigger:

trigger updateTrigger on Master__c (after update) { 
    if(Trigger.isAfter && Trigger.isUpdate) {
        UpdateDetailClass.UpdateDetailMethod(Trigger.New);
    }  
}
1
  • What the heck is this code supposed to accomplish? It looks like chaotic arbitrary reparenting...whichever Master__c record is last in the trigger collection will take all the detail records for itself...
    – Adrian Larson
    Commented Jan 12, 2017 at 13:38

2 Answers 2

1

There's a problem in your code. You select some Detail__c objects which depends on a Master__c object. But after that you loop through all your Master__c objects and all your Detail__c objects. So all your Detail__c objects will be set using the last Master__c object of your for loop.

Here's the solution:

public static void UpdateDetailMethod(List<Master__c> masterList) {

        Set<Id> masterIds = new Set<Id>();

        for(Master__c master : masterList) {
            masterIds.add(master.Id);  
        }

        Map<Id, List<Detail__c>> detailListByMasterId = new Map<Id, List<Detail__c>>();
        for(Detail__c detail : [SELECT Id, Master__c, Master__r.isSelected__c, Type__c FROM Detail__c WHERE Master__c IN: masterIds]){
             if(detailListByMasterId.containsKey(detail.Master__c)){
                 detailListByMasterId.get(detail.Master__c).add(detail);
             }else{
                 List<Detail__c> details = new List<Detail__c>();
                 details.add(detail);
                 detailListByMasterId.put(detail.Master__c, details);
             }
        }

        List<Detail__c> detailToUpdate = new List<Detail__c>();

        for(Master__c master : masterList) {
            if(detailListByMasterId.containsKey(master.Id)){
                for(Detail__c d : detailListByMasterId.get(master.Id)) {
                    if(master.isSelected__c == true) {
                        d.Type__c = master.Type__c;
                        detailToUpdate.add(d);
                    }  
                }
            }
        }

        update detailToUpdate;     

    } 

With this, you are assigning the Master__c Type__c only to the Detail__c records linked to this Master__c object.

5
  • I tried to implement your code but field update on child record is still not happening. I checked the debug logs, and it gives me this line DEBUG|detailToUpdate().
    – lol
    Commented Jan 12, 2017 at 14:58
  • 1
    This must be because your field isselected is set to false for all your master records no? Commented Jan 12, 2017 at 15:00
  • hey man, it's working now. I just made some adjustments and it's working as expected. Thank you very much!!!
    – lol
    Commented Jan 12, 2017 at 15:09
  • by the way, does the approach of yours prevents the so-called governor limits issue in apex?
    – lol
    Commented Jan 12, 2017 at 15:12
  • 1
    You're welcome. There will be no problem with the governor limits. You only make on SOQL query with this code. The only limit is on the number of records you can return with this query. The maximum is 50000. Commented Jan 12, 2017 at 15:17
0

A pattern that works well for this case is to query the detail objects with the related master fields queried at the same time (as you are doing). That then keeps the logic simple and efficient because the values of the master fields can be directly obtained from the detail instances via the relationship field (rather than via loops as you are trying to do or via maps):

public class UpdateDetailClass {

    public static void UpdateDetailMethod(List<Master__c> masterList) {

        Detail__c[] updates = new Detail__c[] {};
        for (Detail__c d : [
                SELECT Id, Type__c, Master__r.Id, Master_r.isSelected__c, Master__r.Type__c
                FROM Detail__c
                WHERE Master__c IN: masterList
                ]) {
            if (d.Master_r.isSelected && d.Master__r.Type__c != d.Type__c) {
                updates.add(new Detail__c(Id = d.Id, d.Master__r.Type__c));
            }
        }
        update updates;
    }

}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .