You need to sign in to do that
Don't have an account?
HARSHIL 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:
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:
Here is a list view of parent object
If I update list view of child with as Mass Update,
the parent records gets updated like this,
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..
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:
Here is a list view of parent object
If I update list view of child with as Mass Update,
the parent records gets updated like this,
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..
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
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>
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!
<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>
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....