[SalesForce] Error when executing batch apex from anonymous apex code

I need to do one time data update in the org. I plan to do this using batch apex. As this is one time update, I don't want to move batch class to production and don't want to write apex unit tests for it.

I am trying to define batch class in anonymous apex and call it from anonymous apex.
Overall structure of anonymous apex is as follows –

 public class batchsample implements Database.Batchable<sObject> {     


     public string query;

     public Database.QueryLocator start(Database.BatchableContext BC)
     {     
       return Database.getQueryLocator(query);
     }

     public void execute(Database.BatchableContext BC, List<sObject> Scope)
     {
          List<customobj__c> ListToUpdate = new List<customobj__c>();

          for(sobject s: Scope)      
          {
             customobj__c m1 = (customobj__c)s;
             //update some fields here
             ListToUpdate.add(m1);
          }
          if(ListToUpdate.size() > 0)
             update ListToUpdate;
     }

     public void finish(Database.BatchableContext BC)
     {
         //send email      

     }
   } 

batchsample startbatch = new batchsample();
startbatch.query = SOQL query goes here
System.scheduleBatch(startbatch, 'samplebatch', 1, 100);

But when I execute above code as anonymous apex, I get an error

Error – Only top-level classes can implement Database.Batchable

Can someone help me understand why this error is given ?
And if there is a way to call batch apex from anonymous apex where Batch Class definition is also part of anonymous apex code ?

Best Answer

Basically, when you call Execute Anonymous, it puts your code within a function within an unnamed class. This has the effect of causing anything you write within to be considered in the context of a class.

In fact, if you look at the logs for an Execute Anonymous, you'll see something like this:

CUMULATIVE_PROFILING External entry point: public static void execute(): executed 1 time in 0 ms

So, we can determine that our code is basically placed into a function called execute() in a temporary class.

We can do many things that we can do in a regular class context. You can write static functions:

static void a() { }

But, despite being a "static"-like execution context, you don't need to declare functions as static to access them:

void a() { }

You can't declare static functions inside a class, because inner classes can't have static methods:

class A {
    static void B() { }  // Won't compile
}

Similarly, we can't implement any interfaces that require top-level contexts, including schedulable, queueable, and batchable, because inner classes do not support these interfaces.

As an aside, AsyncApexJob requires an ApexClassId to be scheduled, but your compiled code is never persisted to the database, and therefore does not have an ApexClassId to attach to. Similarly, inner classes don't have their own unique ID, which is why you can't schedule inner classes for later execution.

Related Topic