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
The WordSlingerThe WordSlinger 

Trouble Synchronizing Contacts with Accounts

I have a situation where I'm trying to implement a synching of a set of information between Accounts and Contacts, regardless of which object level the information is updated. I have built out the custom code to synch Account information to all contacts when it's changed at the Account level but I'm running into weirdness in the Trigger and code when the Contact level information is updated. It should flow logically like this:

  1. Information is updated at one of the contact records
  2. The code updates the information ont he parent Account of that contact
  3. The code then queries all of the contacts related to that parentAccount and updates the information there as well

I want to prevent recursion so I need to somehow exclude the originating contact from the query in step 3.

 

Here is my trigger:

trigger ContactbeforeUpdateTrigger on Contact (before update) {
	
	List<Contact> changedContacts = new List<Contact>();
	
	for (Integer i = 0; i < Trigger.new.size(); i++) {	
			if( 
			(Trigger.old[i].Competitive_Owner__c != Trigger.new[i].Competitive_Owner__c)) {
				changedContacts.add(Trigger.new[i]);
			}
			
			if(!changedContacts.isEmpty()){
			
			ContactServices.syncContactsToAccountandRelatedContacts(changedContacts);
		}
	}
}

 

 

Here is my Apex Class and the method called from the Trigger:

public with sharing class ContactServices { 

Public static void syncContactsToAccountandRelatedContacts (List<Contact> changedContacts){
	List<Account> accountsToUpdate = new List<Account>();
	List<Contact> contactsToUpdate = new List<Contact>();
		
	for (Integer i = 0; i < changedContacts.size(); i++) {		        	
		changedContacts[i].Account.Competitive_Owner__c= changedContacts[i].Competitive_Owner__c;	  
            	accountsToUpdate.add(changedContacts[i].Account);
        }
        update accountsToUpdate;

		
	contactsToUpdate = [Select id, accountId, Competitive_Owner__c From Contact Where accountId in: 
						accountsToUpdate];
						
	for (Integer i = 0; i < contactsToUpdate.size(); i++){
	     contactstoUpdate[i]Competitive_Owner__c = contactstoUpdate[i].Account.Competitive_Owner__c ;	
	updatedContacts.add(c); 
	}
	update updatedContacts;
}
nandurinanduri

Quick fix: Change the triiger event to after update.

If the problem still persists refer a similar example @ 

http://www.salesforce.com/docs/developer/cookbook/Content/apex_controlling_recursive_triggers.htm

sfdcfoxsfdcfox

nandun is correct. Here's a sample I took the time to write up:

 

trigger updateAccountsFromContacts on Contact (after insert, after update) {
	// Find all account ID values
	Set<Id> accountIds = new Set<Id>();
	
	for(Contact c:Trigger.new)
		if(c.accountid != null;
			accountIds.add(c.accountId);

	// query all account values for comparison (next step)
	Map<Id,Account> accounts = new Map<Id,Account>([select id,(select id from contacts where competitive_owner__c<>account.competitive_owner__c),competitive_owner__c from account where id in :accountIds]);
	Map<Id,Account> updates = new Map<Id,Account>();
	
	// Check and see if competitive_owner__c needs to change on the account, and if the rest of the contacts are in sync.
	// It is an error to have two contacts on the same account in the same batch being updated to different values (conflict).
	for(contact c:trigger.new)
		if(c.competitive_owner__c != accounts.get(c.accountid).Competitive_Owner__c || !accounts.get(c.accountid).contacts.isEmpty())
			if(updates.containsKey(c.accountid) && updates.get(c.accountid).Competitive_Owner__c != c.Competitive_Owner__c)
				c.addError('Competitive Owners has unresolvable conflict. Please review the contacts in this batch.');
			else
				updates.put(c.accountid,new account(id=c.accountid,competitive_owner__c=c.competitive_owner__c));
	
	// Update any accounts that need to be changed or to sync the account's other contacts.
	update updates.values();
}
trigger updateContactsFromAccounts on Account (after update) {

	// Find all contacts to update.
	List<Contact> contacts = new List<Contact>();
	
	// We will look for contacts that do not have the same value as the account that are in this trigger.
	for(Contact c:[select id,accountid,competitive_owner__c from contact where accountid in :trigger.new and competitive_owner__c!=account.competitive_owner__c])
		contacts.add(new contact(id=c.id,competitive_owner__c=trigger.newmap.get(c.accountid).competitive_owner__c));
	
	// After this point, all accounts in the trigger and their contacts will be synchronized.
	update contacts;
}

Includes conflict detection and guaranteed synchronization after edit of any record on a given account (when deployed to an organization with initially inconsistent data).