You need to sign in to do that
Don't have an account?

How to update all child records??
Hi,
I have a master detail relationship between Opportunity( as master) and Custom object (as detail).
I want to update all the detail records, if i change / update any detail record. I mean all the detail records should contain same value. If i am changing any record, that should get changed other detail records as well..
trigger updateallRequisitions on Opportunity (after update) {
List < Id > OppsIds = new List < Id >();
List < Id > RRIds = new List < Id >();
for(Opportunity rem: Trigger.New) {
if(rem.test__c != 'Closed'){
List<RR__c> proObj = [select p.Id,p.Bill_Rate__c from RR__c p where p.Opportunity__c =:rem.Id];
if(proObj.size() > 0){
for(RR__c pc: proObj ){
pc.Bill_Rate__c = rem.test__c ;
update pc;
}
}
}
}
}
Thanks
I thought that the current validation would take care of that but I was wrong, sorry about that. I will explicitly exclude the calling record and that should take care of the problem. Here is the code:
}
trigger setValue on RR__c (before update)
{
List<ID> OppIDs = new List<ID>();
Boolean needsUpdate = FALSE;
for (RR__c RRs: trigger.new)
{
OppIDs.add(RRs.Opportunity__c);
}
List<RR__c> otherRR = new List<RR__c>([select id, Bill_Rate__c,Opportunity__c from RR__c where Opportunity__c in: OppIDs]);
for (RR__c RRs: trigger.new)
{
for (integer i=1; i < otherRR.size(); i++)
{
if ((otherRR[i].Opportunity__c == RRs.Opportunity__c) && (otherRR[i].Bill_Rate__c != RRs.Bill_Rate__c) && (otherRR[i].id != RRs.id))
{
otherRR[i].Bill_Rate__c = RRs.Bill_Rate__c;
needsUpdate = TRUE;
}
}
}
if (needsUpdate){
update otherRR;
}
That is strange cause this logic otherRR[i].Bill_Rate__c != RRs.Bill_Rate__c should preclude the calling record from adding itself to the list, but the red check should resolve it.
All Answers
Hello, the trigger that you have written is firing when the opprotunity is being Updated not when a RR__c record is being updated. It sounds from your description that you want this to fire when the RR__c record is being edited. That being said, below I have fixed your trigger to do what your trigger was trying to do:
Notice I pulled all of your SOQL statements out of any for loops and we are only calling Update one time. This is good practice to avioid hitting governor limits with these statements during bulk updates.
Finally, if you do need it the way that you described and not the way you wrote it, let me know and I will modify the trigger to reflect that.
Hope this helps.
Agree with Jake, just a minor optimisation suggestion
Given that its an after udpate trigger, trigger.newMap will be available, so you wouldn't need to iterate and aggregate your opportunity ids, you could use IN :trigger.NewMap directly.
Hi Jake,
I should have explain the need in much specific way.. as it was creating ambiguity..
Yes, i want the trigger to update all RR__c records, if i update any RR__c record (with the updated value), i mean i want this to fire when any RR__c record is being edited..need is something that i have described...
Thanks
OK so here is a trigger that should get you going:
I have not tested the code above in a live environment, but I do something similar in my org and I modeled the trigger after one I already have so barring any syntax errors it should be OK.
Good Luck, I hope this works for you.
Hi Jake,
I am getting the following error while implementing the below posted trigger: Please have a look..
"setValue: execution of BeforeUpdate
caused by: System.SObjectException: SObject row was retrieved via SOQL without querying the requested field: RR__c.Opportunity__c
Trigger.setValue: line 14, column 46"
trigger setValue on RR__c (before update)
{
List<ID> OppIDs = new List<ID>();
Boolean needsUpdate = FALSE;
for (RR__c RRs: trigger.new)
{
OppIDs.add(RRs.Opportunity__c);
}
List<RR__c> otherRR = new List<RR__c>([select id, Bill_Rate__c from RR__c where Opportunity__c in: OppIDs]);
for (RR__c RRs: trigger.new)
{
for (integer i=0; i <= otherRR.size(); i++)
{
if (RRs.Opportunity__c == otherRR[i].Opportunity__c || otherRR[i].Bill_Rate__c != RRs.Bill_Rate__c) <line 14>
{
otherRR[i].Bill_Rate__c = RRs.Bill_Rate__c;
needsUpdate = TRUE;
}
}
}
if (needsUpdate){
update otherRR;
}
}
All you have to do is add opportunity__c to your query.
}
trigger setValue on RR__c (before update)
{
List<ID> OppIDs = new List<ID>();
Boolean needsUpdate = FALSE;
for (RR__c RRs: trigger.new)
{
OppIDs.add(RRs.Opportunity__c);
}
List<RR__c> otherRR = new List<RR__c>([select id, Bill_Rate__c, Opportunity__c from RR__c where Opportunity__c in: OppIDs]);
for (RR__c RRs: trigger.new)
{
for (integer i=0; i <= otherRR.size(); i++)
{
if (RRs.Opportunity__c == otherRR[i].Opportunity__c || otherRR[i].Bill_Rate__c != RRs.Bill_Rate__c) <line 14>
{
otherRR[i].Bill_Rate__c = RRs.Bill_Rate__c;
needsUpdate = TRUE;
}
}
}
if (needsUpdate){
update otherRR;
}
Hi,
I am getting the following error while editing the record...
setValue: execution of BeforeUpdate
caused by: System.ListException: List index out of bounds: 4
Trigger.setValue: line 14, column 22
Note <where 4, is the total number of records for that opportunity)
It is because in your for loop you have <= instead of <, id did not notice it last time cause I just looked at the line you underlined. This line:
for (integer i=0; i <= otherRR.size(); i++)
needs to become:
for (integer i=0; i < otherRR.size(); i++)
This is because arrays start at 0 not 1 so the for loop as you have it written is looping 5 times not 4, so essentially otherRR has four elements otherRR[0], otherRR[1], otherRR[2], otherRR[3], but you code is trying to access otherRR[4] which does not work.
Hi Jake, I tried the same.. but was getting the following error:
Error: Invalid Data. Review all error messages below to correct your data. Apex trigger setValue caused an unexpected exception, contact your administrator: setValue: execution of BeforeUpdate caused by: System.DmlException: Update failed. First exception on row 0 with id a0IL00000009T1kMAE; first error: SELF_REFERENCE_FROM_TRIGGER, Object (id = a0IL00000009T1k) is currently in trigger setValue, therefore it cannot recursively update itself: []: Trigger.setValue: line 22, column 5
trigger setValue on RR__c (before update)
{
List<ID> OppIDs = new List<ID>();
Boolean needsUpdate = FALSE;
for (RR__c RRs: trigger.new)
{
OppIDs.add(RRs.Opportunity__c);
}
List<RR__c> otherRR = new List<RR__c>([select id, Bill_Rate__c,Opportunity__c from RR__c where Opportunity__c in: OppIDs]);
for (RR__c RRs: trigger.new)
{
for (integer i=1; i < otherRR.size(); i++)
{
if ((otherRR[i].Opportunity__c == RRs.Opportunity__c) && (otherRR[i].Bill_Rate__c != RRs.Bill_Rate__c))
{
otherRR[i].Bill_Rate__c = RRs.Bill_Rate__c;
needsUpdate = TRUE;
}
}
}
if (needsUpdate){
update otherRR;
}
}
I thought that the current validation would take care of that but I was wrong, sorry about that. I will explicitly exclude the calling record and that should take care of the problem. Here is the code:
}
trigger setValue on RR__c (before update)
{
List<ID> OppIDs = new List<ID>();
Boolean needsUpdate = FALSE;
for (RR__c RRs: trigger.new)
{
OppIDs.add(RRs.Opportunity__c);
}
List<RR__c> otherRR = new List<RR__c>([select id, Bill_Rate__c,Opportunity__c from RR__c where Opportunity__c in: OppIDs]);
for (RR__c RRs: trigger.new)
{
for (integer i=1; i < otherRR.size(); i++)
{
if ((otherRR[i].Opportunity__c == RRs.Opportunity__c) && (otherRR[i].Bill_Rate__c != RRs.Bill_Rate__c) && (otherRR[i].id != RRs.id))
{
otherRR[i].Bill_Rate__c = RRs.Bill_Rate__c;
needsUpdate = TRUE;
}
}
}
if (needsUpdate){
update otherRR;
}
That is strange cause this logic otherRR[i].Bill_Rate__c != RRs.Bill_Rate__c should preclude the calling record from adding itself to the list, but the red check should resolve it.
Hi Jake,
This time i didn't get any error... :) but my other records are not getting updated...
i mean.. lets say i have 4 records for an opportunity..and i update the value for field Bill_Rate__c for one record.. then it should get copied (i.e. update) other records as well, but that is not happening....
That is my fault this needs to be an after update trigger so your first line should be
trigger setValue on RR__c (after update)
you can also add a comma after after update and add after insert if you want the trigger to run on new records as well.
Hi Jake,
Many Thanks for taking this forward and finally resolve it. I am marking the solution accepted.. so that other people can get benefit out of it....thanks
Your welcome
Hi jake,
this should be my last query on this..i believe...
Currently all my records gets updated.. based on the changes made out in one particular record..earlier.. it was for a single field (Bill_Rate__c)..now i need the same thing should get happen on other 10 selected fields also...I mean whenever any changes will be made in those 10 fields.. it will get replicated in all the records...i changed the code and achieved the same...
But, there is one trouble doing that...lets say i have created two records one by one with different field values all together... and now, if i make any change in one record it gets replicated in another record...because both the records exists for a single opportunity...
to identify that these two records are different..we have a standard field.. CREATEDDATE.. which is different in both the records...now, if i try to update the records using this field.. i get the following error:
UpdateRequisitions: System.LimitException: Too many script statements: 200001
My current Code:
trigger UpdateRequisitions on Requisition__c (after update)
{
List<ID> OppIDs = new List<ID>();
Boolean needsUpdate = FALSE;
for (Requisition__c RRs: trigger.new)
{
OppIDs.add(RRs.Opportunity__c);
}
List<Requisition__c> otherRR = new List<Requisition__c>([select id,CREATEDDATE,Priority__c,RR_Status__c,RM_Phase__c,Role__c,Long_Term_Resource_Location__c,New_Position__c,Required_Skill__c,Years_of_Experience__c,Opportunity__c from Requisition__c where Opportunity__c in: OppIDs]);
for (Requisition__c RRs: trigger.new)
{
for (integer i=0; i < otherRR.size(); i++)
{
if ((otherRR[i].Opportunity__c == RRs.Opportunity__c) && (otherRR[i].id != RRs.id)
&& (otherRR[i].CREATEDDATE == RRs.CREATEDDATE)
&& ((otherRR[i].Priority__c != RRs.Priority__c)
|| (otherRR[i].RR_Status__c != RRs.RR_Status__c)
|| (otherRR[i].RM_Phase__c != RRs.RM_Phase__c)
|| (otherRR[i].Role__c != RRs.Role__c)
|| (otherRR[i].Long_Term_Resource_Location__c != RRs.Long_Term_Resource_Location__c)
|| (otherRR[i].New_Position__c != RRs.New_Position__c)
|| (otherRR[i].Required_Skill__c != RRs.Required_Skill__c)
|| (otherRR[i].Years_of_Experience__c != RRs.Years_of_Experience__c)))
{
otherRR[i].Bill_Rate__c = RRs.Bill_Rate__c;
otherRR[i].Priority__c = RRs.Priority__c;
otherRR[i].RR_Status__c = RRs.RR_Status__c;
otherRR[i].RM_Phase__c = RRs.RM_Phase__c;
otherRR[i].Role__c = RRs.Role__c;
otherRR[i].Long_Term_Resource_Location__c = RRs.Long_Term_Resource_Location__c;
otherRR[i].New_Position__c = RRs.New_Position__c;
otherRR[i].Required_Skill__c = RRs.Required_Skill__c;
otherRR[i].Years_of_Experience__c = RRs.Years_of_Experience__c;
needsUpdate = TRUE;
}
}
}
if (needsUpdate)
{
update otherRR;
}
}
Nancy, this problem is much more difficult to debug than the others. You are running up against APEX Governor limits. For more information you can read about them here:
http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_gov_limits.htm
If you look you can see that you can only execute 200000 code statements and you are going over that. The question is why. There are several different things that you can look at to figure it out.
First thing to think about is: Is this a manual update (from the Salesforce UI) or are you using the Dataloader or API? From what we have talked about I believe that this is a manual update, but it never hurts to be sure. This matters because Salesforce does batch processing when the dataloader and/or the API are used and that could have pushed you over the governor limits.
Next, consider the number of records being updated. Essentially consider how many rows the query, List<Requisition__c> otherRR = ...; is returning. You can play with that by adding a LIMIT statment to the very end of the query before the ). Essentially start with LIMIT 1 and see if it runs on some test data and increase the LIMIT from there to see what the threshold is. Once you figure that out you can make some decisions from there. You can also go back to the last time that you had the code working and add changes a piece at a time so that you can see exactly what breaks the code. Then you can use the following to figure out why it is breaking the code.
If neither of those leads to the cause of the problem the last place to look is the debug log. First you have to set up monitoring. Goto Setup->Monitoring->Debug Logs and set up yourself as a monitored user. Then recreate the error (ie Update a record that causes the error. Then go back up to Your Name->System Logs. Make sure you are using the new System Log and then clear the "This Session Only" check box. You should see the log for your execution there and be able to look through it to see what is going on as the Trigger runs.
My feeling is that you will find your problem in the Debug Log. It is possible that you are somehow ending up in an infinite loop and that is why you are hitting the Governor Limit. Essentially when you call Update otherRR, each of those records will trigger the Trigger seperately, but they run under the same Governor Limits as the original trigger. So essentially a record could be getting updated, update another record and that record could be updating the original record again resulting in an infinite loop. The Debug log will show you if this is happening.
Some tips on the debug log
1. You can look at the debug log for a successful execution as well. So you can roll back your trigger to some code that you know works and look at the log for that and see what the differences are between and valid and invalid execution.
2. You can use system.debug('Some message here'); in your code to break up the debug log and easily find what is executing here. You can even do something like system.debug('message in my for loop i=' + i) to see which iteration of the for loop you are on.
3. For more info on the System Log you can look here:
http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_debugging_system_log_console.htm
I hope this helps you find your problem. If you have any questions let me know and I will do my best to answer them.
Also I was looking at your code one last time to see if I can figure out where the infinite loop (assuming that it is a loop that is your problem) is coming from and I was wondering in your if statement you have this:
(otherRR[i].CREATEDDATE == RRs.CREATEDDATE)
from your description you seem to want this:
(otherRR[i].CREATEDDATE != RRs.CREATEDDATE)
because you want records where the CREATEDDATE is different not the same.