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
Donna Whitig 34Donna Whitig 34 

Update Contact fields with Account field data

I need to update contacts that are chosen on lookup fields on an account to have the same values on custom fields as associated account. 
Background:
  • I have two fields on the Account object that lookup directly to the contact object to house Primary Contact 1 and Primary Contact 2.
  • The Account object has two custom fields Main_Page_Access__c and Sub_Page Access__c.  The Contact object has these same custom fields.
  • I want to run a nightly routine that will update the Main_Page_Access__c, Sub_Page Access__c fields on the Contact object with the values from the Account object.  I need help with the Apex class to do the updates.  
I was able to query the Account and get the Primary Contact 1's ID along with the Account ID and the access fields from the Account and add this to a list.  I then did a second query for the Primary Contact 2 and added that to the list.  Now I want to loop through that list and use the Account Main_Page_Access__c, Sub_Page_Access__c field information to update the contacts Main_Page_Access__c, Sub_Page_Access__c fields.  This is where I am stuck.  Keep in mind that I am new to Apex development...  :-)


***********  Here's my code so far ******************

public with sharing class Assign_Access {

    public static void SelectContactsAndAccess() {

        //Find the Account that have Primary Contacts Associated with them

    //Create a list to hold all primary contacts and access information

        List<Account> AllContacts = new List<Account>();
        AllContacts.clear();

    //Fetch first primary contact and add to PrimaryContact1 list where Primary_Contact1__c holds the Contact ID

        List<Account> PrimaryContact1 = [SELECT Id, Name, Primary_Contact1__c, 
                                             Main_Page_Access__c, Sub_Page_Access__c
                                         FROM Account 
                                         WHERE Primary_Contact__c != NULL ];      

        System.debug('PrimaryContact1 ' + PrimaryContact1);

    //Add Primary Contact 1 to AllContacts list

        AllContacts.addall(PrimaryContact1);

    //Fetch second primary contact and add to PrimaryContact2 list where Primary_Contact2__c holds the Contact ID 

        List<Account> PrimaryContact2 = [SELECT Id, Name, Primary_Contact2__c, 
                                Main_Page_Access__c, Sub_Page_Access__c
                                FROM Account 
                                WHERE Primary_Contact2__c != NULL ]; 

        System.debug('PrimaryContact2 ' + PrimaryContact2);

    //Add Primary Contact 2 to AllContacts list

        AllContacts.addall(PrimaryContact2);

        system.debug('AllContacts '+ AllContacts);

}
}
Best Answer chosen by Donna Whitig 34
Abdul KhatriAbdul Khatri
public with sharing class Assign_Access {

    public static void SelectContactsAndAccess() {
		
        //Contact List for Updates
        List<Contact> contactsToUpdate = new List<Contact>();              

        //Collecting Account List where either Primary Contact 1 OR Primary Contact 2 available
        //I made loop into loop as this is a best practise to handle limits it is called SOQL Loop
        for (List<Account> acccountList : [SELECT Id, Name, Primary_Contact1__c, Main_Page_Access__c, Sub_Page_Access__c FROM Account WHERE Primary_Contact1__c != NULL OR Primary_Contact2__c != NULL])
        {
			
            for(Account account : acccountList )
            {
            	//this check is self explanatory
                if(account.Primary_Contact1__c != null) {
                	//adding to contact update list
                    contactsToUpdate.add(getContactForUpdate(account.Primary_Contact1__c, account));
                }
    
                if(account.Primary_Contact2__c != null) {
                
                    contactsToUpdate.add(getContactForUpdate(account.Primary_Contact2__c, account));
                }
    
            }      
            
            if(!contactsToUpdate.isEmpty())
                update contactsToUpdate;        
        }
    
    }
    
    private static Contact getContactForUpdate (Id idContact, Account account) {
   	
       //getting the instance of the Contact for Update for the Id 
       Contact contact = new Contact (Id = idContact);
       contact.Main_Page_Access__c = account.Main_Page_Access__c;
       contact.Sub_Page_Access__c = account.Sub_Page_Access__c;       
       
       return contact;
   }    
}

Please give a try now. Sorry I made contactToUpdate List of Account instead of Contact

All Answers

Abdul KhatriAbdul Khatri
Please find the code that should fulfill your requirement. I refactored the code.
 
public with sharing class Assign_Access {

    public static void SelectContactsAndAccess() {

        List<Account> contactsToUpdate = new List<Account>();              
    
        for (List<Account> acccountList : [SELECT Id, Name, Primary_Contact1__c, Main_Page_Access__c, Sub_Page_Access__c FROM Account WHERE Primary_Contact1__c != NULL OR Primary_Contact2__c != NULL])
        {

            for(Account account : acccountList )
            {
            
                if(account.Primary_Contact1__c != null) {
                
                    contactsToUpdate.add(getContactForUpdate(account.Primary_Contact1__c, account));
                }
    
                if(account.Primary_Contact2__c != null) {
                
                    contactsToUpdate.add(getContactForUpdate(account.Primary_Contact2__c, account));
                }
    
            }      
            
            if(!contactsToUpdate.isEmpty())
                update contactsToUpdate;        
        }
    
    }
    
    private static Contact getContactForUpdate (Id idContact, Account account) {
   
       Contact contact = new Contact (Id = idContact);
       contact.Main_Page_Access__c = account.Main_Page_Access__c;
       contact.Sub_Page_Access__c = account.Sub_Page_Access__c;       
       
       return contact;
   }    
}

 
Donna Whitig 34Donna Whitig 34
Thanks Abdul for such a quick response!  Would you mind throwing in some comments so I can follow what you have done?
Abdul KhatriAbdul Khatri
tried my best
public with sharing class Assign_Access {

    public static void SelectContactsAndAccess() {
		
        //Contact List for Updates
        List<Account> contactsToUpdate = new List<Account>();              

        //Collecting Account List where either Primary Contact 1 OR Primary Contact 2 available
        //I made loop into loop as this is a best practise to handle limits it is called SOQL Loop
        for (List<Account> acccountList : [SELECT Id, Name, Primary_Contact1__c, Main_Page_Access__c, Sub_Page_Access__c FROM Account WHERE Primary_Contact1__c != NULL OR Primary_Contact2__c != NULL])
        {
			
            for(Account account : acccountList )
            {
            	//this check is self explanatory
                if(account.Primary_Contact1__c != null) {
                	//adding to contact update list
                    contactsToUpdate.add(getContactForUpdate(account.Primary_Contact1__c, account));
                }
    
                if(account.Primary_Contact2__c != null) {
                
                    contactsToUpdate.add(getContactForUpdate(account.Primary_Contact2__c, account));
                }
    
            }      
            
            if(!contactsToUpdate.isEmpty())
                update contactsToUpdate;        
        }
    
    }
    
    private static Contact getContactForUpdate (Id idContact, Account account) {
   	
       //getting the instance of the Contact for Update for the Id 
       Contact contact = new Contact (Id = idContact);
       contact.Main_Page_Access__c = account.Main_Page_Access__c;
       contact.Sub_Page_Access__c = account.Sub_Page_Access__c;       
       
       return contact;
   }    
}

 
Donna Whitig 34Donna Whitig 34
Thanks!
Abdul KhatriAbdul Khatri
Did you try?
Abdul KhatriAbdul Khatri
Please don’t forget to mark this best if helped
Donna Whitig 34Donna Whitig 34
Hi Abdul, I am getting the error message "Method does not exist or incorrect signature: void add(Contact) from the type List" for the following two lines. contactsToUpdate.add(getContactForUpdate(account.Primary_Contact__c, account)); contactsToUpdate.add(getContactForUpdate(account.Primary_Contact_B__c, account)); Any thoughts?
Donna Whitig 34Donna Whitig 34
Sorry should have been but still getting error "Method does not exist or incorrect signature: void add(Contact) from the type List" contactsToUpdate.add(getContactForUpdate(account.Primary_Contact1__c, account)); contactsToUpdate.add(getContactForUpdate(account.Primary_Contact2__c, account));
Abdul KhatriAbdul Khatri
public with sharing class Assign_Access {

    public static void SelectContactsAndAccess() {
		
        //Contact List for Updates
        List<Contact> contactsToUpdate = new List<Contact>();              

        //Collecting Account List where either Primary Contact 1 OR Primary Contact 2 available
        //I made loop into loop as this is a best practise to handle limits it is called SOQL Loop
        for (List<Account> acccountList : [SELECT Id, Name, Primary_Contact1__c, Main_Page_Access__c, Sub_Page_Access__c FROM Account WHERE Primary_Contact1__c != NULL OR Primary_Contact2__c != NULL])
        {
			
            for(Account account : acccountList )
            {
            	//this check is self explanatory
                if(account.Primary_Contact1__c != null) {
                	//adding to contact update list
                    contactsToUpdate.add(getContactForUpdate(account.Primary_Contact1__c, account));
                }
    
                if(account.Primary_Contact2__c != null) {
                
                    contactsToUpdate.add(getContactForUpdate(account.Primary_Contact2__c, account));
                }
    
            }      
            
            if(!contactsToUpdate.isEmpty())
                update contactsToUpdate;        
        }
    
    }
    
    private static Contact getContactForUpdate (Id idContact, Account account) {
   	
       //getting the instance of the Contact for Update for the Id 
       Contact contact = new Contact (Id = idContact);
       contact.Main_Page_Access__c = account.Main_Page_Access__c;
       contact.Sub_Page_Access__c = account.Sub_Page_Access__c;       
       
       return contact;
   }    
}

Please give a try now. Sorry I made contactToUpdate List of Account instead of Contact
This was selected as the best answer
Donna Whitig 34Donna Whitig 34
Thank you - works great! Now I have to figure out how to schedule it to run nightly. I was reading here: https://help.salesforce.com/articleView?id=code_schedule_batch_apex.htm&type=5 It looks to me that I need to write another Apex class that instantiates the Assign_Access class then I can call that via the Apex Scheduler but I'm not sure how to do that. I've looked at some examples but they are not clear to me. Can you point me in the direction of any good examples?
Abdul KhatriAbdul Khatri
Here is the schedul job. Read this article to know all about schedulable apex
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_scheduler.htm

In the Developer Console => Open Execute Anonymous Window, execute the following commands to start and stop the job
ContactAccessUpdateJob.start();
ContactAccessUpdateJob.stop();
global class ContactAccessUpdateJob implements Schedulable {

    public static String jobname = 'Set Contact Page Access';
    public static String CRON_EXP = '0 05 0 * *  ?'; //Run every night at 1:05
    global list<Id> idOppList = new List<Id>();
   
    public ContactAccessUpdateJob (){

    }
    
    public static void Start()
    {
        System.schedule(jobName, CRON_EXP, new ContactAccessUpdateJob());
    }   
    
    
    public static void Stop()
    {
        List<CronJobDetail> jobs = [SELECT Id FROM CronJobDetail WHERE Name = :jobName];
        
        if(!jobs.isEmpty()) {
            for(CronJobDetail job : jobs) {
                Id jobId = [SELECT Id from CronTrigger WHERE CronJobDetailId = :job.Id][0].Id;
                System.abortJob(jobId); 
            }           
        }
    }
    
    global void execute(SchedulableContext SC)
    {
        Assign_Access.SelectContactsAndAccess();   
    }
    
}
You should be able to see the jobs navigating as shown below

User-added image

 
Donna Whitig 34Donna Whitig 34
Thanks, I think this is a bit over my head at this point.   Thanks for all of your help and sticking with me. :-)
Donna Whitig 34Donna Whitig 34
I see the job in the scheduler! Question - What is the purpose of the line " global list idOppList = new List();"? I don't see where the list is referenced anywhere else in the code. Was that just left over from an example you had? Thanks!
Abdul KhatriAbdul Khatri
Yes you are correct, sorry for that.