[SalesForce] Trigger to update field in opportunity when account is created with same value as in the field of account

I have the lookup field New_Contact__c in Account and Opportunity.When I create New_ Contact__c in Account record and save ,the same value should be populated on to Opportunity lookup field New_ Contact__c.

I wrote the below trigger to update opportunity field based on value in account field.

Trigger:

trigger contactupdation on Account (after update) {
        Set<ID> OppAcc = New Set<id>();
        List<Opportunity> opps = New List<Opportunity>();
        
        for(Account a : Trigger.New)
        {
            OppAcc.add(a.Id);
        }        
        Map<Id, Opportunity> mapOppty = new Map<Id, Opportunity>([SELECT Id, Primary_Contact__c FROM Opportunity where Id IN :OppAcc]);
        for(Account acc : Trigger.New){
            Opportunity opp = mapOppty .get(acc.Id);
            opp.Primary_Contact__c= acc.Primary_Contact__c;
            opps.add(opp);
        }
            update opps;
        
}

Error: contactupdation: execution of AfterUpdate caused by: System.NullPointerException: Attempt to de-reference a null object Trigger.contactupdation: line 16, column 1

I got this error while creating New_Contact__c Field in Account.

Anyone help me solve this Scenario.

Thanks,
Jane

Best Answer

Opportunity opp = mapOppty .get(acc.Id);

This will always be null; the Id for this map is the Opportunity Id, not the Account Id. Also, it doesn't properly handle the situation of multiple opportunities per account. In addition, it doesn't check if any work needs to be done, wasting CPU time and queries.

Ideally, you should just do this with a Process Builder flow. No need to get Apex involved.

However, this is how I'd fix it:

Opportunity[] updates = new Opportunity[0];
for(Opportunity record:[SELECT AccountId,New_Contact__c FROM Opportunity WHERE AccountId = :Trigger.new]) {
  Account accountRecord = Trigger.newMap.get(record.AccountId).New_Contact__c;
  if(record.New_Contact__c != accountRecord.New_Contact__c) {
    record.New_Contact__c = accountRecord.New_Contact__c;
    updates.add(record);
  }
}
update updates;

You could also just restrict the update to when actual changes occur:

Account[] changes = new Account[0];
for(Integer i = 0, s = Trigger.new.size(); i < s; i++) {
  if(Trigger.new[i].New_Contact__c != Trigger.old[i].New_Contact__c) {
    changes.add(Trigger.new[i]);
  }
}
Opportunity[] updates = new Opportunity[0];
for(Opportunity record:[SELECT AccountId,New_Contact__c FROM Opportunity WHERE AccountId = :changes]) {
  Account accountRecord = Trigger.newMap.get(record.AccountId);
  if(record.New_Contact__c != accountRecord.New_Contact__c) {
    record.New_Contact__c = accountRecord.New_Contact__c;
    updates.add(record);
  }
}
update updates;