+ Start a Discussion
kryan0618kryan0618 

Update After Trigger: Update same object

 

Hi, I am new to APEX development. I have created a new trigger to update a custom field on the Lead object. I have to use 'after update' since I need to have the OwnerId. It works, however, I just KNOW it is not properly coded. Can someone please review and let me know how it really should be? Especially regarding what is referred to as ‘bulkification’?

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

trigger UpdateLeadOwner2AfterInsertUpdate on Lead (after insert, after update) {

 

string txtLdID;



for (Lead newLead : [Select Id,OwnerId,Lead_Owner_2__c from Lead where Id in :Trigger.new]) {
        
// Update the Lead Record
        txtLdID = newLead.OwnerId;
        if (newLead.Lead_Owner_2__c <> newLead.OwnerId && txtLdID.startsWith('00G') == FALSE) {
          newLead.Lead_Owner_2__c = newLead.OwnerId;
          update newLead;
        }  
              
    }
        
}

Best Answer chosen by Admin (Salesforce Developers) 
Shailesh DeshpandeShailesh Deshpande
1. The update statement is inside the loop. Remove it. Have a list of Leads, add the individual records to the list at the place where you have written the update statement. And outside the loop, issue an update statement on the list.

2. Since you are updating the same object, this will result in recursive trigger. So you can have a boolean field(default value true), which you set to false while you update the record. If the value of this field is false, dont fire the trigger.

3. Other option would be to have a class and a static boolean variable in that class. Set this field to false before you issue the update statement and add an if statement before the 1st line of your trigger. IF(BOOLEANVARIABLE){your trigger code}

4. If your trigger is only for updating owners, you can add a condition in the for loop:

if(l.ownerId != Trigger.OldMap().get(l.Id).ownerId)
{then proceed}

All Answers

Jeff MayJeff May

Generally speaking, if you want to update the object that is in the trigger, you'd want to do that in a before trigger, not an after trigger.  

 

 

kryan0618kryan0618

Yes, that would be ideal. But since I am dealing with Leads and we have Lead Assignment Rules, I need the record after all updates and it has been committed to the database so I have the current OwernId.

Jeff MayJeff May

in that case, since you have to... :)

 

in your after trigger, you can create a new object and set its ID to the Id of the trigger object.  All the same 'bulkifying' rules apply.

 

for (Lead l : trigger.new) {

    Lead ld = new Lead(Id = l.id);

}

kryan0618kryan0618

I don't need to create a new object, I just need to update the leads that were changed. Is my code correct for the trigger I created? As I stated, the current trigger works, but I want to be creating and writing efficient code.

 

Thanks for your help!

Jeff MayJeff May

in an after trigger, the object in the trigger is read-only, you will not be able to just update the fields as you would in a before trigger.

Shailesh DeshpandeShailesh Deshpande
1. The update statement is inside the loop. Remove it. Have a list of Leads, add the individual records to the list at the place where you have written the update statement. And outside the loop, issue an update statement on the list.

2. Since you are updating the same object, this will result in recursive trigger. So you can have a boolean field(default value true), which you set to false while you update the record. If the value of this field is false, dont fire the trigger.

3. Other option would be to have a class and a static boolean variable in that class. Set this field to false before you issue the update statement and add an if statement before the 1st line of your trigger. IF(BOOLEANVARIABLE){your trigger code}

4. If your trigger is only for updating owners, you can add a condition in the for loop:

if(l.ownerId != Trigger.OldMap().get(l.Id).ownerId)
{then proceed}
This was selected as the best answer
kryan0618kryan0618

Shailesh,

 

I actually did end up changing the code to the following. I might have made it more complex than necessary since I am dealing with the same object, but it works. Adding the code for the recursive issue is a good call. I will look into that, as well. Thanks!!

 

trigger UpdateLeadOwner2AfterInsertUpdate on Lead (after insert, after update) {

    string txtLdID;
    
    Set<Id> leadIds = new Set<Id>();
    
    //create a list of the records that need updating
    for (Lead oLead : trigger.new) {
            txtLdID = oLead.OwnerId; 
            if (oLead.Lead_Owner_2__c <> oLead.OwnerId && txtLdID.startsWith('00G') == FALSE) {
                leadIds.add(oLead.Id);
             }
      }  
    
    //Iterate through all records that need updating
    If (leadIds.isEmpty() == false) {
        List<Lead> listLeads = [SELECT id, OwnerId, Lead_Owner_2__c  from Lead WHERE Id in :leadIds];
        For (Lead oLead : listLeads) {
            oLead.Lead_Owner_2__c = oLead.OwnerId;
         }
        //Post the changes to the database
        If (listLeads.isEmpty() == false) {
            Update listLeads;
        }
    }
}

Shailesh DeshpandeShailesh Deshpande
Ryan,

your earlier code was perfect except few changes which I suggested. The code that you posted now also does the same job, but the second for loop is not needed. You can do the same thing in your 1st for loop.