+ Start a Discussion
HARSHIL U PARIKHHARSHIL U PARIKH 

Trigger shows unexpected behavior when Mass updating all child records From the list View

Hello Developers!

I need your help in following.
I have two objects with lookup relationship 1) Projects__c Parent and 2) Participants__c as child
Requirement: Create roll up summary on parent to count all devoted hours from child.
My trigger:
Trigger CountHours On Participants__c (After Insert, After Update, After Delete, After Undelete){
    
    List<Participants__c> Parti = New List<Participants__c>();
    Set<ID> ProjIds = New Set<ID>();
    
    if (!Trigger.isDelete)
    {
        for (Participants__c PC: Trigger.New)
        {
        ProjIds.add(PC.Project__c);
        }
    }
    else 
    { 
       for (Participants__c PC: Trigger.old)
        {
        ProjIds.add(PC.Project__c);
        }
    }
    Parti = [Select Devoted_Hours__c From Participants__c where Project__c IN: ProjIds];
    Double X = 0;
    for(Integer I = 0; I<Parti.size(); I++){
        if(Parti[I].Devoted_Hours__c != null){
            X += Parti[I].Devoted_Hours__C;
        } 
    }
    List<Projects__c> Projs = New List<Projects__c>([Select Total_Devoted_Hours__c From Projects__c Where ID IN: ProjIds]);
   if (!Trigger.isDelete){
            for(Participants__c Partici: Trigger.New){   
                for (Projects__c P: Projs){ 
                     P.Total_Devoted_Hours__c = X;
                }
            }
        }
        else {
            for(Participants__c Partici: Trigger.Old){    
                for (Projects__c P: Projs ){ 
                    P.Total_Devoted_Hours__c = X;
                }
            }
        }
    
    update Projs;
 
}

This trigger works fine for when record is inserted, updated deleted, or even undeleted but strange thing is when I update all child records from list views (using Mass Update App), all parents gets updated with the sum of devoted hours.
How?
Here is a list view of child object:
User-added image
Here is a list view of parent object
User-added image
If I update list view of child with as Mass Update, 
the parent records gets updated like this,
User-added image
 I am wondering why all of the project got updated with total of all Participants__c's devoted hours?
Thank You for the help guys..
Best Answer chosen by HARSHIL U PARIKH
GarryPGarryP
Your logic is wrong .
Watch out LOC 30 to 31 in your code. here you are just copy pasting same X in all the project records. Single inset, update, delete should work finebutu thsi fails in mass udpate of childs which is expected. 

Also avoid using for inside a for loo LOC29 and 30. The code is too bad and would create issues (might be working ok for now)

You should create the MAP n all such cases
here is the updated code. i have not tested this but this should work. Let me know in case of any issues

<pre>
Trigger CountHours On Participants__c (After Insert, After Update, After Delete, After Undelete) {
    List<Participants__c> Parti = New List<Participants__c>();
    Set<ID> ProjIds = New Set<ID>();
    List<Participants__c> listTriggerParticipants;
    if (!Trigger.isDelete) {
        listTriggerParticipants = (List<Participants__c>)Trigger.New;
        /* for (Participants__c PC : Trigger.New) {
             ProjIds.add(PC.Project__c);
         }*/
    }
    else {
        listTriggerParticipants = (List<Participants__c>)Trigger.old;
        /* for (Participants__c PC : Trigger.old) {
             ProjIds.add(PC.Project__c);
         }*/
    }
    //Just one For Loop, removed redundancy
    for (Participants__c PC : listTriggerParticipants) {
        ProjIds.add(PC.Project__c);
    }
    /* Use AggregateResults Query instread of un-neccesary for loops
    Enhanced performace
    Parti = [Select Devoted_Hours__c From Participants__c where Project__c IN: ProjIds];
    Double X = 0;
    for (Integer I = 0; I < Parti.size(); I++) {
        if (Parti[I].Devoted_Hours__c != null) {
            X += Parti[I].Devoted_Hours__C;
        }
    }*/
    //Use meaningful names
    Double dDevotedHrs = 0;
    //use map to create rollup for each project record
    Map<Id, Double> mapDevotedHrPerProject = new  Map<Id, Double>();
    //new AggregateResult query
    for (AggregateResult ar : [Select Project__c, SUM(Devoted_Hours__c) totalDevotedHrs
                               From Participants__c
                               where Project__c IN: ProjIds
                               group by Project__c ])  {
        dDevotedHrs = Double.valueOf(ar.get('totalDevotedHrs'));
        mapDevotedHrPerProject.put(Project__c, dDevotedHrs);
    }
    //USe For loops
    //List<Projects__c> Projs = New List<Projects__c>([Select Total_Devoted_Hours__c From Projects__c Where ID IN: ProjIds]);
    List<Projects__c> listProjs = new List<Projects__c>();
    //Save SOQL here and juste uterate over the map at LOC 35
    For(String eachProjectID : mapDevotedHrPerProject.keySet() ) {
        Projects__c eachProject = new Projects__c(id = eachProjectID,
                Total_Devoted_Hours__c = mapDevotedHrPerProject.get(eachProjectID));
        listProjs.add(eachProject);
    }
    //This is not needed, as we already know what all project records need an Update.
    /*if (!Trigger.isDelete) {
        for (Participants__c Partici : Trigger.New) {
            for (Projects__c P : Projs) {
                P.Total_Devoted_Hours__c = X;
            }
        }
    }
    else {
        /*for (Participants__c Partici : Trigger.Old) {
            for (Projects__c P : Projs ) {
                P.Total_Devoted_Hours__c = X;
            }
        }
    }*/
    //use readbale names
    //update Projs;
    update listProjs;
}
</pre>

All Answers

GarryPGarryP
Your logic is wrong .
Watch out LOC 30 to 31 in your code. here you are just copy pasting same X in all the project records. Single inset, update, delete should work finebutu thsi fails in mass udpate of childs which is expected. 

Also avoid using for inside a for loo LOC29 and 30. The code is too bad and would create issues (might be working ok for now)

You should create the MAP n all such cases
here is the updated code. i have not tested this but this should work. Let me know in case of any issues

<pre>
Trigger CountHours On Participants__c (After Insert, After Update, After Delete, After Undelete) {
    List<Participants__c> Parti = New List<Participants__c>();
    Set<ID> ProjIds = New Set<ID>();
    List<Participants__c> listTriggerParticipants;
    if (!Trigger.isDelete) {
        listTriggerParticipants = (List<Participants__c>)Trigger.New;
        /* for (Participants__c PC : Trigger.New) {
             ProjIds.add(PC.Project__c);
         }*/
    }
    else {
        listTriggerParticipants = (List<Participants__c>)Trigger.old;
        /* for (Participants__c PC : Trigger.old) {
             ProjIds.add(PC.Project__c);
         }*/
    }
    //Just one For Loop, removed redundancy
    for (Participants__c PC : listTriggerParticipants) {
        ProjIds.add(PC.Project__c);
    }
    /* Use AggregateResults Query instread of un-neccesary for loops
    Enhanced performace
    Parti = [Select Devoted_Hours__c From Participants__c where Project__c IN: ProjIds];
    Double X = 0;
    for (Integer I = 0; I < Parti.size(); I++) {
        if (Parti[I].Devoted_Hours__c != null) {
            X += Parti[I].Devoted_Hours__C;
        }
    }*/
    //Use meaningful names
    Double dDevotedHrs = 0;
    //use map to create rollup for each project record
    Map<Id, Double> mapDevotedHrPerProject = new  Map<Id, Double>();
    //new AggregateResult query
    for (AggregateResult ar : [Select Project__c, SUM(Devoted_Hours__c) totalDevotedHrs
                               From Participants__c
                               where Project__c IN: ProjIds
                               group by Project__c ])  {
        dDevotedHrs = Double.valueOf(ar.get('totalDevotedHrs'));
        mapDevotedHrPerProject.put(Project__c, dDevotedHrs);
    }
    //USe For loops
    //List<Projects__c> Projs = New List<Projects__c>([Select Total_Devoted_Hours__c From Projects__c Where ID IN: ProjIds]);
    List<Projects__c> listProjs = new List<Projects__c>();
    //Save SOQL here and juste uterate over the map at LOC 35
    For(String eachProjectID : mapDevotedHrPerProject.keySet() ) {
        Projects__c eachProject = new Projects__c(id = eachProjectID,
                Total_Devoted_Hours__c = mapDevotedHrPerProject.get(eachProjectID));
        listProjs.add(eachProject);
    }
    //This is not needed, as we already know what all project records need an Update.
    /*if (!Trigger.isDelete) {
        for (Participants__c Partici : Trigger.New) {
            for (Projects__c P : Projs) {
                P.Total_Devoted_Hours__c = X;
            }
        }
    }
    else {
        /*for (Participants__c Partici : Trigger.Old) {
            for (Projects__c P : Projs ) {
                P.Total_Devoted_Hours__c = X;
            }
        }
    }*/
    //use readbale names
    //update Projs;
    update listProjs;
}
</pre>
This was selected as the best answer
HARSHIL U PARIKHHARSHIL U PARIKH
HI Girish, Thank you for the replay and more importantly thanks for writing the importance of each line.
I am trying to execute the code but it says Error: Compile Error: Variable does not exist: Project__c at line 40 column 36
Appreciated!
GarryPGarryP
   updated local 35 to 41. 
<pre> for (AggregateResult ar : [Select Project__c eachProject, SUM(Devoted_Hours__c) totalDevotedHrs
                               From Participants__c                            where Project__c IN: ProjIds
                         group by Project__c ])  {
    dDevotedHrs = Double.valueOf(ar.get('totalDevotedHrs'));
mapDevotedHrPerProject.put(String.valueOf(ar.get('eachProject')), dDevotedHrs);
  }</pre>
HARSHIL U PARIKHHARSHIL U PARIKH
Hello Girish, Thank you so much for followup.
This child object (Participants__c ) above is also a child of several other Custom parent objects (e.g., Projects__c, X__c, Y__c, Z__c etc..) so when I create a record on Participants__c for it's one of other parent X__c or Y__c or Z__c and don't enter value on field "Projects__c" then it throws an error as:

Error: Invalid Data. 
Review all error messages below to correct your data.
Apex trigger CountHours caused an unexpected exception, contact your administrator: CountHours: execution of AfterInsert caused by: System.DmlException: Update failed. First exception on row 0; first error: MISSING_ARGUMENT, Id not specified in an update call: []: Trigger.CountHours: line 68, column 1

Again, thakyou though....