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
Mahesh Babu 187Mahesh Babu 187 

Trigger to populate a look-up field based on another look-up field

Hi Team,

I am stuck in a trigger. I have 2 look-up fields on Product obejct. Through first look-up field i.e  'Parent Id'  we can select Account Name and through second look-up field we select Account Manager Name. Now my requirement is as i select the Account Name in first look-up field, it should automatically populate respective Account Manager Name in second look-up field  .
I have created the trigger.

trigger AddAccountManager on Product2 (before update) {
        Set<Id> Ids = new Set<Id>();
    for(Product2 p : Trigger.new){
        Ids.add(p.Parent_ID__c);
    }
    Map<Id, Account> accountownername = new Map<Id , Account>([SELECT id, Name, AccountManager__c FROM Account WHERE Id IN: Ids]);
    for(Product2 p : Trigger.new){
        if(p.Parent_ID__c != null && accountownername.containsKey(p.Parent_ID__c))   {
            p.Account_Manager__c = accountownername.get(p.Parent_ID__c).AccountManager__c;
        }
    }
     }  

I am getting this error:

Apex trigger AddAccountManager caused an unexpected exception, contact your administrator: AddAccountManager: execution of AfterUpdate caused by: System.FinalException: Record is read-only: ()

Please help me to solve this.

Thanks,
Mahesh
Best Answer chosen by Mahesh Babu 187
Mahesh Babu 187Mahesh Babu 187
Hi Kritika,

i have solved the issue.

MODIFIED CODE

trigger AddAccountManager on Product2 (after update) {
    
    if(checkRecursive.runOnce()){  
    
        for(Product2 p : Trigger.new){
            Product2 product = [Select Parent_ID__c, Account_Manager__c FROM PRODUCT2 WHERE Id =: p.Id];
            Account account = [Select Account_Manager__c FROM Account WHERE Id =: product.Parent_ID__c];
            System.debug('account: '+account.Account_Manager__c);
            product.Account_Manager__c = account.Account_Manager__c;
            update product;        
        }
    }   
}

All Answers

Abhishek BansalAbhishek Bansal
Hi Mahesh,

In the error it is clearly mentioned that the execution of After Update is failed. Please check if you have any other trigger on the same object that runs on After Update context. We are not allowed to update the trigger records in after context.

Thanks,
Abhishek Bansal.
Mahesh Babu 187Mahesh Babu 187
Hi Abhishek,
I have deleted the other trigger on the same object and modified my code but still I am getting same issue. i have also used before update event but it doesn't do anything.

CODE

trigger AddAccountManager on Product2 (after update) {
    
    if(checkRecursive.runOnce()){
        
    Set<Id> Ids = new Set<Id>();
    for(Product2 p : Trigger.new){
        Ids.add(p.Parent_ID__c);
        System.debug('Parent_ID__c: '+Ids);
    }
    Map<Id, Account> accountownername = new Map<Id , Account>();
        for(Account acc : [SELECT id, ParentId, Name, AccountManager__c FROM Account WHERE Id IN: Ids]){
            accountownername.put(acc.Id, acc);
        }
        System.debug('AccountOwnerName: '+accountownername);
        
             if(accountownername.size() > 0){
                    for(Product2 p : Trigger.new){
                     if(p.Parent_ID__c != null && accountownername.containsKey(p.Parent_ID__c)){
                        p.Account_Manager__c = accountownername.get(p.Parent_ID__c).AccountManager__c;
                            System.debug('Account Manager Name: '+p.Account_Manager__c);  
                }
            }
        }      
      
     }   
}

Could you please tell what needs to be modified in my code?

Thanks,
Mahesh
Kritika RajKritika Raj
If your requirement is that whenever the Account Lookup field on Product is updated then the Account Manager Field on Product should get populated with the respective Account Manager , then you dont need to do this in After update . Usually when the automation is on the same object we use before triggers . This link will help you to undestand when to use before and after triggers https://www.sfdc99.com/2014/01/25/use-vs-triggers/

You can modify your code based on the following code - 
trigger ProductTrigger on Product2 (before insert ,before update) {
     
    if(Trigger.isInsert || Trigger.isUpdate) {
        ProductTriggerHelper.populateAccountManager(Trigger.new);
    }

}
 
public class ProductTriggerHelper {
    
    public static void populateAccountManager(List<Product2> productslist) {
        
        Set<Id> accIds = new Set<Id>();
        
        for(Product2 prod : productslist) {
            
            if(prod.Account__c != null)
                accIds.add(prod.Account__c);
            
        }
        
        Map<Id,Id> accWithAccOwner = new Map<Id,Id>();
        for(Account acc : [SELECT Id,OwnerId FROM Account WHERE Id IN: accIds]) {
            accWithAccOwner.put(acc.Id , acc.OwnerId);
        }
        
        for(Product2 prod : productslist) {
            
            if(accWithAccOwner.containsKey(prod.Account__c))
                prod.Account_Manager__c = accWithAccOwner.get(prod.Account__c);
            else
               prod.Account_Manager__c = null; 
        }
    }

}

Please let me know if you have any further queries and if it helps you to resolve the issue then mark it as a best answer so that others could use it for reference.
Mahesh Babu 187Mahesh Babu 187
Hi Kritika,

i have solved the issue.

MODIFIED CODE

trigger AddAccountManager on Product2 (after update) {
    
    if(checkRecursive.runOnce()){  
    
        for(Product2 p : Trigger.new){
            Product2 product = [Select Parent_ID__c, Account_Manager__c FROM PRODUCT2 WHERE Id =: p.Id];
            Account account = [Select Account_Manager__c FROM Account WHERE Id =: product.Parent_ID__c];
            System.debug('account: '+account.Account_Manager__c);
            product.Account_Manager__c = account.Account_Manager__c;
            update product;        
        }
    }   
}
This was selected as the best answer
Kritika RajKritika Raj
Hi Mahesh , its good that your code is working but if someone will update more than 50 records together then your code will break as the governor limit will exceed because you are using 2 SOQL queries inside a for loop . You should always avoid using SOQL and DML Statements inside a for loop .