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
Ben MertonBen Merton 

Cross object field update

This is my first attempt at an APEX trigger or any kind of Apex.

I am trying to update a field in a child object from a field in a parent object.  It is giving an error on line 4:  Parent_Object.Parent_Custom_Field__r variable is not found

ie a Parent_Custom_Field__c from Parent_Object__c into the Child_Object__c Child_Custom_Field__c

trigger NEWTRIGGER on Child_Object__c (before insert) {

    For (Child_Object__c ChildField : Trigger.new)
        
    {ChildField.Child_Custom_Field=Parent_Object.Parent_Custom_Field__r;
    }
}
Best Answer chosen by Ben Merton
pigginsbpigginsb
Hi, Ben.

You will need to build up a set of parent record Ids in order to query for these parent records, as they will not be part of your trigger data by default. I would advise querying them directly into a Map<Id, Parent_Object__c> as this will automatically put the Parent Object's Id values as the key, and the Parent Record as the value.

Then by iterating over the child records in trigger.new, you can use the parent record's Id to get the necessary parent record from the map, then update the child record with the appropriate value.
 
Set<Id> parentIdSet = new Set<Id>(); // new parent id set

for (Child_Object__c eachChildRecord : trigger.new)
     parentIdSet.add(eachChildRecord.parentId__c); // parentId__c is considered the lookup field to the parent object

Map<Id, Parent_Object__c> parentMap = new Map<Id, Parent_Object__c>([select Parent_Custom_Field__c from Parent_Object__c where Id in :parentIdSet]); // the query result as the map parameter automatically populates the map

for (Child_Object__c eachChildRecord : trigger.new) {
     if (eachChildRecord.parentId__c == null)
          continue; // this will avoid attempting to populate the child field if no parent exists, might not apply in your case

     Parent_Object__c parentRecord = parentMap.get(eachChildRecord.parentId__c); // get appropriate parent record from the map
     eachChildRecord.Child_Custom_Field__c = parentRecord.Parent_Custom_Field__c; // write parent's value to child record
}
Hope this helps you get going!
 

All Answers

pigginsbpigginsb
Hi, Ben.

You will need to build up a set of parent record Ids in order to query for these parent records, as they will not be part of your trigger data by default. I would advise querying them directly into a Map<Id, Parent_Object__c> as this will automatically put the Parent Object's Id values as the key, and the Parent Record as the value.

Then by iterating over the child records in trigger.new, you can use the parent record's Id to get the necessary parent record from the map, then update the child record with the appropriate value.
 
Set<Id> parentIdSet = new Set<Id>(); // new parent id set

for (Child_Object__c eachChildRecord : trigger.new)
     parentIdSet.add(eachChildRecord.parentId__c); // parentId__c is considered the lookup field to the parent object

Map<Id, Parent_Object__c> parentMap = new Map<Id, Parent_Object__c>([select Parent_Custom_Field__c from Parent_Object__c where Id in :parentIdSet]); // the query result as the map parameter automatically populates the map

for (Child_Object__c eachChildRecord : trigger.new) {
     if (eachChildRecord.parentId__c == null)
          continue; // this will avoid attempting to populate the child field if no parent exists, might not apply in your case

     Parent_Object__c parentRecord = parentMap.get(eachChildRecord.parentId__c); // get appropriate parent record from the map
     eachChildRecord.Child_Custom_Field__c = parentRecord.Parent_Custom_Field__c; // write parent's value to child record
}
Hope this helps you get going!
 
This was selected as the best answer
Ben MertonBen Merton
Thank you for this!  I am slowly grappling with the concepts of sets and maps.  This really helped.  However, I am getting this error when the code is deployed.  The custom field I am triggering into is a lookup field.  Does that complicate things?

Apex trigger CAPANC caused an unexpected exception, contact your administrator: CAPANC: execution of AfterUpdate caused by: System.FinalException: Record is read-only: Trigger.CAPANC: line 15, column 1
pigginsbpigginsb
The error is occurring because your trigger is firing After Update. If your trigger were to fire Before Update (or Before Insert, which your original question suggested), then the child records are still on their way into the database, and you would be able to write to that field. The records would take their updated value with them into the database. Unless their's more to the trigger than weve discussed, it seems like you can go with a before trigger here.

Trigger.new in an After Update, After Insert, or After Undelete trigger is the version of the record that is already in the database, and does not get saved to the database again. If your trigger needs to be After Update, then you will need to collect the records you want to update into a separate list and perform an update on that list. (This would require some additional work also, because that update would fire the same trigger again).

Documentation on this: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_triggers_context_variables.htm

Something else comes to mind, the work of this trigger could also be accomplished with a workflow rule/field update, because you are traversing up to the parent record to get another of its values and writing it to the child record. Your field update formula would look like this: "Parent_Object__c.Parent_Custom_Field__c", would be set to update "Child_Custom_Field__c", and the workflow rule could be set to fire whenever the record is updated or when it is updated and the Child_Custom_Field__c is null.