2

I am writing a trigger on Account to update the phone number of all the contacts associated with it,with the phone number of that account. (I understand this is possible using Process builder, However I am trying to get some hands on Triggers).I have written a Before update trigger. Below is the logic.

public static void onBeforeUpdate( Map<Id,Account> newAccountMap)
{
   For(Contact c : [Select Id,AccountId from Contact where AccountId in : newAccountMap.keyset()])
   {
     c.Phone = newAccountMap.get(c.AccountId).Phone ; 
   }
}

When I update the phone on an account record from lets say XXXXX123 to XXXXX456, all the contacts associated with it still have phone values as XXXXX123 AND NOT XXXXX456 I looked into the official doc for trigger and it seems Trigger.New or Trigger.newMap values are still not yet committed to the database, hence value newAccountMap.get(c.AccountId).Phone returns the existing value in the database and not the new value. Neither we can get the new values of Phone on an account using SOQL.My query is- How can we get New Values from the Trigger.newmap and update the corresponding contact record with the new value.? It works fine with the below After Update trigger

public static void onAfterUpdate( Map<Id,Account> newAccountMap)
{   
   List<Contact> con = New List<Contact> ();
   For(Contact c : [Select Id,AccountId from Contact where AccountId in : newAccountMap.keyset()])
   {
     c.Phone = newAccountMap.get(c.AccountId).Phone ; 
     con.add(c);
   }
   update con;
}

But, I don't want to use After Insert , since I need to use DML as well in an After Insert , which will fire a trigger on contact (which I don't want)

3 Answers 3

1

You absolutely must fire an update on the related Contact records. If you just update fields in memory, the only way those changes will persist to the database is if you are setting fields on the records in trigger.new. It won't work for related records which you have queried.

Any cross-object logic should always occur in after triggers. See, for example:

Triggers

There are two types of triggers:

  • Before triggers are used to update or validate record values before they’re saved to the database.
  • After triggers are used to access field values that are set by the system (such as a record's Id or LastModifiedDate field), and to affect changes in other records, such as logging into an audit table or firing asynchronous events with a queue. The records that fire the after trigger are read-only.
1

A trigger on one object cannot update values of any related record (child or parent) without using DML. There's simply no way around that 1.

If your trigger is on Account, you will need to use DML and have your Contact records fire their own trigger(s).

Since there is a possibility of a loop here (Account updating Contact, which may cause Account to be updated again), I'd recommend looking into including a static set<Id> as a recursion prevention mechanism (in your account trigger, check to see which Ids have already been encountered, and don't process them again. If it's the first time you've seen this Id, add it to your set, and continue processing)

1: With the exception being cross-object workflow field updates, but that only works from child -> parent, seems to require a master-detail relationship, and will cause trigger(s) on the parent object to be run

1

When you iterate Trigger.new you are getting the values that were passed by the user. The previous values (the unchanged record from the database) can be accessed in the Trigger.old list.

  1. Iterate your new account records (preferably while checking if the phone number was actually modified, using the Trigger.oldMap map), get their ids to a set or list.
  2. Get the contacts that refer to the selected accounts.
  3. Iterate the contacts and assign the account phone number to the contacts.
  4. Update the contacts.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .