function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
lizmijohnlizmijohn 

Update child records on parent field update

Hi,

 

I have a custom object by name : Project

Child object name: ProjectAnalysis

 

Based on Project start date, End Date, Project Value, Project value per month in Project object , Project Analysis records will get generated. Please find the Trigger code:

 

trigger ProjectAnalysis on Project__c(after insert,after update) {if(trigger.isafter){   

if(trigger.isinsert)   

{    List<Project_Analysis__c> ProjectAnalysis = new List <Project_Analysis__c> {};    for (Project__c p : trigger.new) {    Integer i = 0;   

date Date1= p.StartDate__c;   

date myDate1=Date1;   

if (i <= (p.No_of_months__c + 1) ) {   

for (myDate1 = myDate1; myDate1 < p.EndDate__c.addDays(20); myDate1= myDate1.addDays(30)) {    ProjectAnalysis.add(new Project_Analysis__c(Project__c= p.Id, Amount_per_month__c= p.Project_Value_per_month__c, Date__c = myDate1));    }   

i=i+1;   

}   

}   

}

 

 

I need help to update the ProjectAnalysis records if there is a change in Project value per month/Start Date/End Date field in Project object on update.

 

Please help me on this.

 

Thanks in advance

Best Answer chosen by Admin (Salesforce Developers) 
Starz26Starz26

So Project Analysis could be multiple records per project? if so, then the map will not work as only the last record would be present....

 

Try this:

 

if(trigger.isupdate){

List<Project_Analysis__c> listPA= new List <Project_Analysis__c> ();
List<Project_Analysis__c> tbuPA = New List<Project_Analysis__c>();


listPA = [Select Project1__c,Amount_Per_Month__c FROM Project_Analysis__c WHERE Project1__c IN :trigger.new];


date myDate1=Date1;

for (Project1__c oProject : trigger.old){ 

   for(Project_Analysis__c lPA : listPA){

       if (lPA.Project1__c == oproject.id && oProject.Project_Value_per_month__c != lPA.Project_Value_per_month__c)
               {           
                   lPA.project_Value_Per_month__c = oProject.project_Value_Per_month__c;
                    tbuPA.add(lPA);
                   
               }  
       }

}     

if(tbuPA.size() > 0)  

update tbuPA;

}

 

All Answers

Starz26Starz26

try using

 

//Set up variables and list

 

Boolean hasChanged = false;

 

if(trigger.isupdate){

 

for(Project__c nP : trigger.new)

 

Project__c oProject = trigger.oldMap.get(a.ID);

 

for(Projectc oP :oProject){

if (oP.Project_Value != nP.Project_Value){

//Set variable values here

hasChanged = true;

}

//check other fields and set values if changed.

 

if(hasChanged){

//add changes to list

hasChanged = false;

}

 

update list;

}

 

You may also need to check to see if a projectanalysis exists or not or use upsert if you will me moving a full record.

lizmijohnlizmijohn

Hi,

 

Thanks for the reply. Since I am new to Triggers, can u help me in correcting the code below:

 

if(trigger.isupdate) {   

Id[]  Names = new Id[]{};   -(Project unique field name is "Name")

for(Project__c nP : trigger.new){   

List<Project_Analysis__c> UpdateProjectAnalysis = new List <Project_Analysis__c> {};  --new list created for child record

List<Project_Analysis__c> children=[Select Name,Amount_per_month__c FROM Project_Analysis__c WHERE Project__c IN:nP.Names];   --Selecting values into child record from Parent

Boolean hasChanged=false;       

 Project__c oProject = trigger.oldMap.get(Names.Id);     --Please let me know what this step means

for(Project__c oP :oProject){   -- --Please let me know what this step means

 if (oP.Project_Value_per_month__c!= nP.Project_Value_per_month__c){          

 

}   //Set variable values

herehasChanged = true;}/

/check other fields and set values if changed. 

if(hasChanged)

{//add changes to listhasChanged = false;} 
    }   

update list;

}   

Starz26Starz26

I updated a few thing. Also you will need to add / change any values on the listPA from Project__c that you are checking

 

if(trigger.isupdate) {   

//Create a List of ProjectAnalysis
ProjectAnalysis__c[]  listPA = new ProjectAnalysis[]{};   -(Project unique field name is "Name")

//Boolean to determine if any values were changed
Boolean hasChanged=false;       

//Get a List of related Project Analysis Records
listPA = [Select ID, Name, Amount_Per_Month__c FROM ProjectAnalysis__c WHERE Project__c IN :trigger.new];

//id will be project_c ID so we can look up ProjectAnalysis by Project__c ID
Map<id,ProjectAnalysis__c> mapOfPA = New Map<id, ProjectAnalysis>();

//Build a map of Project__c to ProjectAnalysis using Project__c ID
for(ProjectAnalysis oPA : listPA)

      mapOfPA(oPA.Project__c, oPA);

//This loops through the new tirgger
for(Project__c nP : trigger.new){   

   //This gets the record by ID before it was changed
   Project__c oProject = trigger.oldMap.get(nP.Id);  

      //This Loops through each old record
      for(Project__c oP :oProject){   -- --Please let me know what this step means

         if (oP.Amount_per_month__c!= nP.Amount_per_month__c){          

               mapOfPA.get(np.id).Amount_Per_Month__c = nP.Amount_Per_Month;

               hasChanged = true;

          }
      }
    }


if(hasChanged)

  update mapOfPA.values()
}   

 

 

lizmijohnlizmijohn

Hi,

 

I have placed the same code:

 

trigger UpdateProjAnalysis on Project__c (after update)

{List<Project_Analysis__c> listPA= new List <Project_Analysis__c> {};
Boolean hasChanged=false;

listPA = [Select ID,Amount_Per_Month__c FROM Project_Analysis__c WHERE Project__c IN :trigger.new];

Map<id,Project_Analysis__c> mapOfPA = New Map<id, Project_Analysis__c>();

for(Project_Analysis__c oPA : listPA)mapOfPA.put(oPA.Project__c, oPA);
for(Project__c nP : trigger.new){Project__c oProject = trigger.oldMap.get(nP.Id); 

for(Project__c oP :oProject)

{if (oP.Project_Value_per_month__c!= nP.Project_Value_per_month__c){ 

mapOfPA.get(np.id).Amount_per_month__c= nP.Project_Value_per_month__c;

hasChanged = true;
          }     

}   

}    

if(hasChanged)  update mapOfPA.values();
}

}

 

I am getting the follwoing error:

 Loop must iterate over a collection type: SOBJECT:Project__c at line 12 column 20

 

line 12: "for(Project__c oP :oProject){"

 

Please help me on this.

Starz26Starz26

Sorry about that: try changing:

 

//This loops through the new tirgger
for(Project__c nP : trigger.new){   

   //This gets the record by ID before it was changed
   Project__c oProject = trigger.oldMap.get(nP.Id);  

      //This Loops through each old record
      for(Project__c oP :oProject){   -- --Please let me know what this step means

         if (oP.Amount_per_month__c!= nP.Amount_per_month__c){          

               mapOfPA.get(np.id).Amount_Per_Month__c = nP.Amount_Per_Month;

               hasChanged = true;

 

to

 

//This loops through the new tirgger
for(Project__c nP : trigger.new){   

   //This gets the record by ID before it was changed
   Project__c oProject = trigger.oldMap.get(nP.Id);  

      
         if (oProject.Amount_per_month__c!= nP.Amount_per_month__c){          

               mapOfPA.get(np.id).Amount_Per_Month__c = nP.Amount_Per_Month;

               hasChanged = true;

 

 

lizmijohnlizmijohn

The code seems to work except for the line at:

 

mapOfPA(oPA.Project__c, oPA);

 

Error: Compile Error: Method does not exist or incorrect signature: mapOfPA(Id, SOBJECT:Project_Analysis__c) at line 31 column 1

 

When I give mapOfPA.put(oPA.Project__c, oPA); the error disappears. But on run, child records do not get updated on chnage of Amount per month value.

Starz26Starz26

You are correct in the .put on the map. I forgot to add that when typing it.

 

Can you add a few lines of debug code and turn on your debug logs. Then post the values of the debug code here to see, or PM them to me?

 

Update the code to this to do some debuging:

 

//id will be project_c ID so we can look up ProjectAnalysis by Project__c ID
Map<id,ProjectAnalysis__c> mapOfPA = New Map<id, ProjectAnalysis>();

//Build a map of Project__c to ProjectAnalysis using Project__c ID
for(ProjectAnalysis oPA : listPA)

      mapOfPA.put(oPA.Project__c, oPA);


system.debug('################### mapOfPA = ' + mapOfPA);


      //This loops through the new tirgger
for(Project__c nP : trigger.new){   

system.debug('################## nP ID = ' nP.ID);

   //This gets the record by ID before it was changed
   Project__c oProject = trigger.oldMap.get(nP.Id);  


system.debug('#################### oProject APM = ' + oProject.Amount_Per_Month__c + ' nP.Amount_Per_Month__c);
      
         if (oProject.Amount_per_month__c!= nP.Amount_per_month__c){          

               mapOfPA.get(np.id).Amount_Per_Month__c = nP.Amount_Per_Month;


system.debug('################ mapOfPA APM = ' + mapOfPA.get(nP.id).Amount_Per_Month);

               hasChanged = true;

          }
      }
    }


if(hasChanged)

  update mapOfPA.values()
}   

 

The ############### are just so you can find it in the log eaisly. Just in case you did not know, you will have to go to Setup -> -> Data Monitoring - > Debug Logs and then click NEW and add your Name. Then when the trigger runs, it will be output to the debug log.

 

Sorry for all the hoops, just trying to figure this out with ya. The debug out put will be helpful in understanding what it is actually doing.

lizmijohnlizmijohn

Sorry for the delay in updating whatz happening with my code :-( Here it goes:

 

Currently only the last record value is getting updated on trigger. I guess some issue with the looping. I am not able to figure it out. Please help.

 

if(trigger.isupdate){
{List<Project_Analysis__c> listPA= new List <Project_Analysis__c> {};

Boolean hasChanged=false;
listPA = [Select Project1__c,Amount_Per_Month__c FROM Project_Analysis__c WHERE Project1__c IN :trigger.new];

Map<id,Project_Analysis__c> mapOfPA = New Map<id, Project_Analysis__c>();

for(Project_Analysis__c oPA : listPA)mapOfPA.put(oPA.Project1__c,oPA);

system.debug('################### mapOfPA = ' + mapOfPA);for(Project1__c nP : trigger.new){date Date1= np.Start_Date__c;
date myDate1=Date1;system.debug('################## nP ID = '+ nP.ID);
for (Project1__c oProject : trigger.old){ 

if (oProject.Project_Value_per_month__c != nP.Project_Value_per_month__c){    mapOfPA.get(oProject.id).Amount_per_month__c = np.Project_Value_per_month__c;       

}  

system.debug('################ mapOfPA APM = ' + mapOfPA.get(nP.id).Amount_per_month__c );
hasChanged = true;

}     

}     

if(hasChanged)  

update mapOfPA.values();

}}}}

Starz26Starz26

So Project Analysis could be multiple records per project? if so, then the map will not work as only the last record would be present....

 

Try this:

 

if(trigger.isupdate){

List<Project_Analysis__c> listPA= new List <Project_Analysis__c> ();
List<Project_Analysis__c> tbuPA = New List<Project_Analysis__c>();


listPA = [Select Project1__c,Amount_Per_Month__c FROM Project_Analysis__c WHERE Project1__c IN :trigger.new];


date myDate1=Date1;

for (Project1__c oProject : trigger.old){ 

   for(Project_Analysis__c lPA : listPA){

       if (lPA.Project1__c == oproject.id && oProject.Project_Value_per_month__c != lPA.Project_Value_per_month__c)
               {           
                   lPA.project_Value_Per_month__c = oProject.project_Value_Per_month__c;
                    tbuPA.add(lPA);
                   
               }  
       }

}     

if(tbuPA.size() > 0)  

update tbuPA;

}

 

This was selected as the best answer
lizmijohnlizmijohn

Thanku for your help. It worked for me. I made few changes in the code, as the code refers to oProject list,it  updated on an alternative basis only.  Please find my code as below:

 

if(trigger.isupdate){
List<Project_Analysis__c> listPA= new List <Project_Analysis__c> ();

List<Project_Analysis__c> tbuPA = New List<Project_Analysis__c>();

listPA = [Select Project1__c,Amount_Per_Month__c FROM Project_Analysis__c WHERE Project1__c IN :trigger.new];

for (Project1__c np : trigger.new) {for (Project1__c oProject : trigger.old){      

for(Project_Analysis__c lPA : listPA){       

if (lPA.Project1__c == np.id && np.Project_Value_per_month__c != lPA.Amount_per_month__c){            lPA.Amount_per_month__c = np.Project_Value_per_month__c;                   

tbuPA.add(lPA);       

 }       }   }   }  

if(tbuPA.size() > 0) update tbuPA;

}}

swarnajaswarnaja

Hai

I am New to Salesfore

I read ur conversation,

But as per my knowledge  a loop with in the another loop is not best practice of apex  coding.

But why are you suggested that solution

I want to know the reason.

If u have the time plz clarify my doubt.

 

Thanks

swarnaja.

Akhil AnilAkhil Anil
This can now easily be achieved using a process builder which is the most efficient point & click solution. The detailed solution for the same has been explained in the below post.

https://force-base.com/2016/10/02/process-builder-update-child-records-based-on-changes-in-the-parent-record/