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
GauravTrivediGauravTrivedi 

How to undelete records using Apex Batch Class.

Hi, 
I was trying to recover record which are accedently deleted from salesforce instance and I am using the following code:
 
global class BatchClass implements Database.Batchable<sObject>,Schedulable{
	global Database.queryLocator start(Database.BatchableContext bc){
		String query = 'SELECT Id, Name, IsDeleted, ItemName__c FROM Buffer__c WHERE IsDeleted = True ALL ROWS';
		return Database.getQueryLocator(query);
	}
	global void execute(Database.BatchableContext BC, List<Buffer__c> scope){
		List<Buffer__c> bufferList = new List<Buffer__c>();
        for(Buffer__c s:scope){
            s.ItemName__c='Gaurav';
            bufferList.add(s);
        }
        system.debug('Data--->'+bufferList);
        undelete bufferList;
    }
	global void finish(Database.BatchableContext bc){
        AsyncApexJob a = [SELECT Id, Status, NumberOfErrors, JobItemsProcessed, TotalJobItems, CreatedBy.Email FROM AsyncApexJob WHERE Id =:BC.getJobId()];
		Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        String[] names = new String[]{a.CreatedBy.Email};
        mail.setToAddresses(names);
        mail.setSubject('Mail: Test');
        mail.setPlainTextBody('Hi ,\n\nThe following job is '+a.Status+' and jobId is '+a.Id+'\n\n\n Regards,\n'+a.CreatedBy.Email);
        Messaging.sendEmail(new Messaging.SingleEmailMessage[]{mail});
	}
    global void execute(SchedulableContext s){
		Database.executeBatch(this);        
    }
}

When I am trying to execute my batch class it doesnt undelete records from recycle bin. Can anyone please help me out. Thanks!
Best Answer chosen by GauravTrivedi
GauravTrivediGauravTrivedi
Thanks for your help. I checked in my environment there was one trigger which restrict records to get undelete because of that my code was not working. Now the same code is working fine. I really appriciate your help man. Thanks :)

All Answers

Lars NielsenLars Nielsen
Let's start simple - the query to return the deleted records looks correct. 

Let's take it apart (outside of batch) and confirm that is working first. I am just typing pseudo-code below outside the IDE
 
List<Buffer__c> recordToUndelete  = [SELECT Id, Name, IsDeleted, ItemName__c FROM Buffer__c WHERE IsDeleted = True ALL ROWS];

System.Debug('***A total of ' + recordToUndelete.size() ' + where found);

try
{
     //attempt to undelete the records
     undelete recordToUndelete;
}
catch(DMLException ex)
{
    System.Debug(ex);
}
catch(Exception e)
{
    System.Debug(e);
}

We essentially just need to make sure the undelete is happening as you expect first then we can move onto batch. Note - just adjust the query to limit the number of rows you get back like you have done above where you only add if ItemName__c = 'Gaurav'
GauravTrivediGauravTrivedi
Lars, 

I tried both ways.
When I am executing the query outside start method it is returning result, but when using inside Start it is giving null.
Lars NielsenLars Nielsen
Okay, so when you run the snippet of code I included (just in the dev console Execute Anonymous) you are getting rows back and it successfully performs the undelete on them? I just want to make sure I am clear on both those points. I just want to make sure we narrow down that we have it working outside batch. When you say inside the start method it is “null” I don’t know what you mean is null. /* snippet from docs on ALL ROWS */ Account[] savedAccts = [SELECT Id, Name FROM Account WHERE Name = 'Trump' ALL ROWS]; Database.UndeleteResult[] UDR_Dels = Database.undelete(savedAccts);
Lars NielsenLars Nielsen
I’m taking a look to see if I can reproduce the same in one of my test accounts…now you’ve got me curious
Lars NielsenLars Nielsen
Okay Gaurav, I ran some tests last night because you got me curious. Here is what I did and I'll attach my results. 
  1. I re-created a skeleton custom object in my org called Buffer__c and I added ItemName__c to it. 
  2. I then populated it with 6 records and deleted two of them
  3. One of the ones I deleted was 'Gaurav' (you can seen in screenshot OrginalTestOnDeleted_Buffer__c.png that it comes back with 2 deleted records)
  4. I then created a stripped down batch class that I could just run on the fly to see a) I was getting the deleted records in the query locator b) that I was making it into the Execute method with those same two records and c) that I was giong through to the finish Method.

Notice I just commented out the scheduleable stuff and I am just kicking this thing off on the fly in Eclipse with the Developer Console open and hoping over to look at the logs.

From everything I can see this stripped down version works properly in batch apex. Here are all the files (including the batch class of yours that I commented some code out of and how I kick it off to test it.)

http://www.salesforcegeneral.com/storage/OrginalTestOnDeleted_Buffer__c.png (http://www.salesforcegeneral.com/storage/OrginalTestOnDeleted_Buffer__c.png" target="_blank)
http://www.salesforcegeneral.com/storage/BatchClass-StartMethod-ReturnsTwoDeletedRecords.png
http://www.salesforcegeneral.com/storage/BatchClass-ExecuteAnonymous.png

http://www.salesforcegeneral.com/storage/BatchClass.cls
http://www.salesforcegeneral.com/storage/DebugLogs-LookGood.png


To kick off the stipped down batch class I just use Eclipse or the Dev Console to Execute Anonymous Apex with the following command
 
BatchClass runBatchClass = new BatchClass();

ID batchprocessid = Database.executeBatch(runBatchClass);
System.debug('Returned batch process ID: ' + batchProcessId);

 
Lars NielsenLars Nielsen
Sorry - All the links above got messed up in the editor and it won't let me edit after posting them for some reason. Here is a zip file with everything above...

http://www.salesforcegeneral.com/storage/BatchClassUndeleteTesting.zip

 
Lars NielsenLars Nielsen
I have also confirmed that at the very end, I uncommented the undelete and re-ran the query and it does in fact undelete properly.
GauravTrivediGauravTrivedi
Thanks for your help. I checked in my environment there was one trigger which restrict records to get undelete because of that my code was not working. Now the same code is working fine. I really appriciate your help man. Thanks :)
This was selected as the best answer
Lars NielsenLars Nielsen
No problem, glad you got it working!
john harvey 2john harvey 2

Hello Lars,

I am trying to retrieve each record that was deleted including the records of my custom object's records and standard object records, How can I acheive that?

jagdish Yadav 10jagdish Yadav 10
Custom object  Flight__c 
public class BatchApexJob Implements Database.Batchable<sObject>{
   
public List<sObject> Start(Database.BatchableContext Bc)
{
    List<Flight__c> FL = [SELECT Id,IsDeleted FROM Flight__c WHERE IsDeleted = True ALL ROWS]; 
  return FL;  
}
    public void execute(Database.BatchableContext Bc,List<sObject> FD){
        undelete FD;
    }
    public void Finish(Database.BatchableContext Bc){
        
    }
}