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
Gyanendra Singh 8Gyanendra Singh 8 

Record update in before trigger

Below lines taken from Salesforce Apex Code Developer's guide:
'if you update or delete a record in its before trigger, or delete a record in its after trigger, you will receive a runtime
error.This includes both direct and indirect operations. For example, if you update account A, and the before update trigger
of account A inserts contact B, and the after insert trigger of contact B queries for account A and updates it using the DML
update statement or database method, then you are indirectly updating account A in its before trigger, and you will receive
a runtime error'


But I can update the Contact description in the before update trigger. Below is the code:

trigger triggerAllContextVariableCheck on Contact (before update, after update, before insert, after insert) {
    if(Trigger.isBefore){
     if(Trigger.isUpdate){
         for(Contact c: trigger.new){
             c.Description='Before Update'; 
         }}}
}

What I am missing? Above code is updating the Contact record in it's before trigger but the statement in the book says something else.

Please explain.

Best Answer chosen by Gyanendra Singh 8
Sameer Tyagi SFDCSameer Tyagi SFDC
Hi  Gyanendra, 

if you update or delete a record in its before trigger, or delete a record in its after trigger, you will receive a runtime
error


It means you can not do any dml like update or delete for the object on which you are writing trigger. 

Here is some example code

trigger triggerAllContextVariableCheck on Contact (before update, after update, before insert, after insert) {
    if(Trigger.isBefore){
     if(Trigger.isUpdate || trigger.isinsert){
list<contact> conlist = new list<contact>();
         for(Contact c: trigger.new){
             c.Description='Before Update'; //Its correct because you are NOT doing any DMLlike update or insert inside it, you are just pre-filling values in description in before operation
        conlist.add(c);
     
         }}}
Update conlist ;// Its incorrect  because you are doing DML, however You can do the same only when you send a list of records in future method of class outside trigger
}

Thanks & Regards, 
Sameer Tyagi

All Answers

PratikPratik (Salesforce Developers) 
Hi Gyanendra,

Your trigger is updating the contact itself. The Salesforce guide says, if you are creating a new record (child) on inser/update event (on parent) which in turn is updating the parent , then it will throw the error.

You can try the account - contact trigger as mentioned in the description to validate it.

Thanks,
Pratik
Gyanendra Singh 8Gyanendra Singh 8

Hi Pratik, but see the first statement it clearly says:

If you update or delete a record in its before trigger, or delete a record in its after trigger, you will receive a runtime
error.This includes both direct and indirect operations

It does not mention that this rule is only for child though just for the sake of giving example they have mentioned the scenario of the parent child. They clearly mentioned "This includes both DIRECT and INDIRECT operations".

 

Gyanendra Singh 8Gyanendra Singh 8

Also can someone explain why the below code does not update the description:

trigger triggerAllContextVariableCheck on Contact (before update) {
    Contact d=[select id, Description from Contact where id='0039000000Mehth'];
    d.Description='Updating in before Trigger';         
}

What is wrong with the above code?

PratikPratik (Salesforce Developers) 
Hi Gyanendra,

You are querying the records on id. In trigger, it will capture the records from either Trigger.new or trigger.old variable.

Here is the code:


trigger updcon on contact(before update) {

    for(contact c: trigger.new) {
    
    c.description='Description through trigger';
    
    }

}


Try above code.

Thanks,
Pratik
Gyanendra Singh 8Gyanendra Singh 8

Pratik I know for sure the above code(written by you) would work. I am not asking for how to update. I am asking what was wrong with the:

rigger triggerAllContextVariableCheck on Contact (before update) {
    Contact d=[select id, Description from Contact where id='0039000000Mehth'];
    d.Description='Updating in before Trigger';         
}
code that it is not updating the description.

And my first question is still partially answered.

Thanks

Sameer Tyagi SFDCSameer Tyagi SFDC
Hi  Gyanendra, 

if you update or delete a record in its before trigger, or delete a record in its after trigger, you will receive a runtime
error


It means you can not do any dml like update or delete for the object on which you are writing trigger. 

Here is some example code

trigger triggerAllContextVariableCheck on Contact (before update, after update, before insert, after insert) {
    if(Trigger.isBefore){
     if(Trigger.isUpdate || trigger.isinsert){
list<contact> conlist = new list<contact>();
         for(Contact c: trigger.new){
             c.Description='Before Update'; //Its correct because you are NOT doing any DMLlike update or insert inside it, you are just pre-filling values in description in before operation
        conlist.add(c);
     
         }}}
Update conlist ;// Its incorrect  because you are doing DML, however You can do the same only when you send a list of records in future method of class outside trigger
}

Thanks & Regards, 
Sameer Tyagi
This was selected as the best answer
PratikPratik (Salesforce Developers) 
Hi Gyanendra,

Your  code:

trigger triggerAllContextVariableCheck on Contact (before update) {
    Contact d=[select id, Description from Contact where id='0039000000Mehth'];
    d.Description='Updating in before Trigger';         
}

In the above code you are specificalluy pointing to Contact record with id=0039000000Mehth. 

When trigger excutes, it will take into the consideration all the records which meet criteria, like here we have Before Update; so any contact record which will get updated will fire the trigger and then the description will be updated.

In your code as you are querying for specific contact record, it will not work.

Thanks,
Pratik
Sameer Tyagi SFDCSameer Tyagi SFDC
Hi Gyanender, 

Trigger triggerAllContextVariableCheck on Contact (before update) {
    Contact d=[select id, Description from Contact where id='0039000000Mehth'];
    d.Description='Updating in before Trigger';         
}

Above code is not working because. 

1. You are not doing it in Trigger.new with before , trigger.new is the list of new instance of records before inserting or updating. 
you can prefill value before inserting and updating without any DML
2. In above code you are quering existing records in salesforce and provide new values in description But NOT updating with DML , Here DML is required, But In case  you can not do DML directly on same object records on which before trigger is written, You have to call it in future method. 



Sameer
 
Gyanendra Singh 8Gyanendra Singh 8

Perfect!!

Thank you Sameer. Your reply perfectly makes sense. I get this now. 

I see that it is absolutely logical, how can we update something in it's before event. It is conflicting.

Now I have one more question, the same code:

Trigger triggerAllContextVariableCheck on Contact (after update) { //note it is after trigger now
    Contact d=[select id, Description from Contact where id='0039000000Mehth'];
    d.Description='Updating in before Trigger'; 
    update d;       
}
 
It throws error. does the same logic apply again? Either
"We cannot do DML directly on same object records on which after trigger is written, We have to call it in future method
" ?

Sameer Tyagi SFDCSameer Tyagi SFDC
Hi Gyanender, 

Thanks!!!
Yes! Same logic apply in this senario. 

If you doing Re-updating values on same object in after trigger ,  you have to call it in future method. 
However you can update the parent record of object directly through DML or 
Create/update child object record of object Directly through DML 


for example 

Trigger triggerAllContextVariableCheck on Contact (after update) { //note it is after trigger now
Id accountid;
  For(Contact con : trigger.new) {    
    accountid = con.accountid;     
 }
Account acc = [select id , name , description from account where id =:accountid];
acc.description = 'New description';
update acc; // direct dml to update parent record
}


Sameer Tyagi 
Gyanendra Singh 8Gyanendra Singh 8
Thank you Sameer for all the replies. Helpful.
Gyanendra Singh 8Gyanendra Singh 8
Sameer but can you little bit clear my doubt as I am not able to figure out what is wrong here logically when we are updating the record in after trigger. The trigger fired after the record is updated that is after the update dml has fired and then m firing the update dml once again and updating the Description field.  So what wrong here logically?
Gyanendra Singh 8Gyanendra Singh 8

I guess I got it. After posting the question I thought about it and this is what I feel, is throwing the error:

After update trigger fires and then I am trying to update a field on the same object and issue an update dml which would again cause after update dml to fire and so on. It would cause the same trigger to be called again and again and finally salesforce would stop executing it and issue the below error:
"maximum trigger depth exceeded".

Hope my understanding is correct

NARESH REDDY 67NARESH REDDY 67
Can anyone help me out what is the mistake i have written..
when i update the record it says dml exception.. can anyone.....
trigger BeforeupdateTestingLead on Testing_Lead__c (before UPDATE) {
    list<Testing_Lead__c> c=new list<Testing_Lead__c>();
    for(Testing_Lead__c x :trigger.new){
        if(x.Address__c!='abc'){
            x.Address__c='banglore';
           c.add(x);
           }      
       insert c;
    }

}
Sourajit MohantySourajit Mohanty
Hi Naresh,
The above code is not working because you are trying to insert while updating the record.
Also, avoid writing DML statements inside for loops to avoid hitting Governor limits.
The code should be as below-
trigger BeforeupdateTestingLead on Testing_Lead__c (before UPDATE) 
{
    list<Testing_Lead__c> c=new list<Testing_Lead__c>();
    for(Testing_Lead__c x :trigger.new)
    {
        if(x.Address__c!='abc')
        {
            x.Address__c='banglore';
            c.add(x);
        }      
    }
    update c;

}