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
ZGZG 

Unable to update original object in a before delete trigger: "System.FinalException: Record is read-only"

In the Context Variable Considerations section of the Apex Developer Guide it is stated that for a before delete trigger:
Can update original object using an update DML operation: Allowed. The updates are saved before the object is deleted, so if the object is undeleted, the updates become visible.

Yet, the code below results in the exception System.FinalException: Record is read-only

Any ideas on how to accomplish this (Waypoint__c is a custom object from one of the trails modules. I added the text field field3__c to it)?
if(Trigger.isDelete)
        {
           
            List<Waypoint__c> lw = new List<Waypoint__c> {};
			for(Waypoint__c w : trigger.old)
            {
                lw.add(w);
            }
            for(Waypoint__c w : lw)
            {
                w.Field3__c = 'BeforeDel';
            }
            
            update lw;
  	}

 
Best Answer chosen by ZG
Sagar PatilSagar Patil
Try this, 
 
trigger beforeDeleteUpdate on Waypoint__c(before delete) {

  if(Trigger.isBefore && Trigger.isDelete){
  
   set<id> del = new set<id>();
   
   for(Waypoint__c  w:Trigger.old)
      {
        del.add(w.id);
      }
  
   List<Waypoint__c> wayList1=[select id from Waypoint__c where id in: del];
   List<Waypoint__c> wayList2= new List<Waypoint__c>();
 
    system.debug('wayList1 size: '+wayList1.size());
   
   for(Waypoint__c  w:wayList1)
     {
        System.debug('IN FOR loop');
        w.Field3__c='XYZ';
        wayList2.add(w);
     }
       
     system.debug('wayList2 size: '+wayList2.size()); 

     try{
        if(wayList2.size()>=1){
           update wayList2;
        } 
    }
  catch(Exception e){
    system.debug('Exception: '+e.getMessage());
  } 
  
}


 

All Answers

HARSHIL U PARIKHHARSHIL U PARIKH
I think its because you are updating the record in before trigger. Try to remove Update statement.

Try this:
 
if(Trigger.isDelete)
        {
           
            List<Waypoint__c> lw = new List<Waypoint__c> {};
			for(Waypoint__c w : trigger.old)
            {
                lw.add(w);
            }
            for(Waypoint__c w : lw)
            {
                w.Field3__c = 'BeforeDel';
            }
            
  	}

Hope this helps!
Raj VakatiRaj Vakati
You can prevent deleting by adding the AddError methods as shown 
if(Trigger.isDelete && Trigger.isBefore)
        {
           
            List<Waypoint__c> lw = new List<Waypoint__c> {};
			for(Waypoint__c w : trigger.new)
            {
               w.adderror('Delete Not allowed');
            }
            
            
   	}



 
ZGZG
Govind, I want to update the original object while in the "before delete" trigger. The documentation says this should be possible.
Raj, I want to update the original object before it is deleted.
Sagar PatilSagar Patil
Try this, 
 
trigger beforeDeleteUpdate on Waypoint__c(before delete) {

  if(Trigger.isBefore && Trigger.isDelete){
  
   set<id> del = new set<id>();
   
   for(Waypoint__c  w:Trigger.old)
      {
        del.add(w.id);
      }
  
   List<Waypoint__c> wayList1=[select id from Waypoint__c where id in: del];
   List<Waypoint__c> wayList2= new List<Waypoint__c>();
 
    system.debug('wayList1 size: '+wayList1.size());
   
   for(Waypoint__c  w:wayList1)
     {
        System.debug('IN FOR loop');
        w.Field3__c='XYZ';
        wayList2.add(w);
     }
       
     system.debug('wayList2 size: '+wayList2.size()); 

     try{
        if(wayList2.size()>=1){
           update wayList2;
        } 
    }
  catch(Exception e){
    system.debug('Exception: '+e.getMessage());
  } 
  
}


 
This was selected as the best answer
ZGZG
Thanks Sagar, your code worked. I was able to verify that field3__c was updated in the before delete trigger. I was also able to verify that the undeleted record had the the field3__c  value set to 'BeforeIns', just as the documentation stated.

Could you please explain why your code worked and mine didn't? I had copied the records in the Trigger.old to a new list, isn't that the way it's supposed to be done?
ZGZG
OK, the code below also works:
List<Waypoint__c> lw = [select id from Waypoint__c where id in: Trigger.oldMap.keyset()];
            for(Waypoint__c w : lw)
            {
                w.Field3__c = 'BeforeDel';
            }
            update lw;

Still don't understand why copying Trigger.old to a new list and updating this new list doesn't work.
ZGZG
I think I know the answer" The Apex Developer Guide states: "Non-primitive data type arguments, such as sObjects, are passed into methods by reference." That's why adding members of Trigger.old to a list and updating them causes an exception: The objects in the list are actually pointing at the objects in Trigger.old.

To test this out, I wrote the code below
Waypoint__c w = new Waypoint__c(name='Test');
List<Waypoint__c> lw1 = new List<Waypoint__c> {};
List<Waypoint__c> lw2 = new List<Waypoint__c> {};
    
lw1.add(w);   
lw2.add(w);
w.field1__c = 'Object itself';
lw1[0].field1__c = 'Updated from lw1';
lw2[0].field1__c = 'Updated from lw2';

system.debug('w.field1__c: ' + w.field1__c);
And sure enought, the debug message is: 09:47:23:002 USER_DEBUG [12]|DEBUG|w.field1__c: Updated from lw2​

The objects in the list above are pointing at the original w object and are not copies of w.