Database Stateful Interface

How To Use Database.Stateful Interface In Batch Apex In Salesforce

1. In Batch apex Changes made by one execute do not transfer to the other execute, so we need to implement  “Database.Stateful” if the batch process needs information that is shared across transactions.

In other words, If you want to transfer the state of the data from one batch to another batch we need to implement “Database.Stateful” interface.

2. If a batch apex class implements “Database.Stateful” interface, the state of the non-static data will be transferred from one execute method to another execute method.

For example:

If we want to check the number of record pass and failed in a batch job, in this particular scenario we need to implement Stateful interface

Example1: Create a custom object “optytmp” with the custom field “Totalamount1”.

Summarize the amount of all the opportunities and create a new optytmp record with an amount as the summarized value of the opportunity.

dont miss out iconDon't forget to check out: Future Methods in Apex | The Salesforce Developer Guide

If we don’t use Database.stateful interface the “Totalamount1” will be Zero as execute method will not pass the data to the finish method.

global class Optystate implements Database.Batchable<Sobject>,Database.stateful {
    global decimal total=0;
    global database.QueryLocator start(database.BatchableContext bc){
        return database.getQueryLocator('select name,amount from opportunity');
    }
    global void execute(database.BatchableContext bc,list<opportunity> op){
        for(opportunity o:op){
            if(o.Amount!=null){
                total=total+o.amount;
            }
        }
        system.debug('=================================== in execute'+total);
    }
    global void finish(database.BatchableContext bc){ system.debug('=================================== in finish'+total); 
    optytmp__c opty=new optytmp__c();
    opty.name='Ravi';
    opty.TotalAmount1__c=total;
    insert opty;
}

Example 2: Calling one batch apex from another and passing the value through constructor.

global class Optystate implements Database.Batchable<Sobject>,Database.stateful {
    global decimal total=0;
    global database.QueryLocator start(database.BatchableContext bc){
        return database.getQueryLocator('select name,amount from opportunity');
    }
    global void execute(database.BatchableContext bc,list<opportunity> op){
        for(opportunity o:op){
            if(o.Amount!=null){
                total=total+o.amount;
            }
        }
        system.debug('=================================== in execute'+total);
    }
    global void finish(database.BatchableContext bc){
        system.debug('=================================== in finish'+total); optytmp__c opty=new optytmp__c();
        opty.name='Test';
        opty.TotalAmount1__c=total;
        insert opty;
        optystate2 os1=new optystate2(total);
        database.executeBatch(os1);
    }
}
global class Optystate2 implements Database.Batchable<Sobject> {
    global decimal total2;
    global Optystate2(decimal total1) {
        total2=total1;
    }
    global database.QueryLocator start(database.BatchableContext bc){
        return database.getQueryLocator('select name,amount from opportunity');
    }
    global void execute(database.BatchableContext bc,list<opportunity> op){
        system.debug('=================================== in finish'+total); optytmp__c opty=new optytmp__c();
        opty.name='Test1'; opty.TotalAmount1__c=total2; insert opty;
    }
    system.debug('=================================== in execute'+total);
    global void finish(database.BatchableContext bc){}
    global class  CheckpassFailBatch Update implements Database.Batchable<sObject>, Database.Stateful {
        global String log = ''; // stateful variable to keep track of errors across batches
        global Database.QueryLocator start(Database.BatchableContext BC){
            String query = 'SELECT Id, Name, NBType__c ';
            query += 'FROM Opportunity ';
            query += 'WHERE ContractStartDate__c != null ';
            query += 'AND ContractStartDate__c > 2014-01-01 ';
            //query += 'AND NBType__c != null ';
            return Database.getQueryLocator(query);
        }
        global void execute(Database.BatchableContext BC, List<sObject> scope){
            system.debug('Processing ' + scope.size() + ' opportunities');
            for (Opportunity opportunity : (List<Opportunity>)scope){
                system.debug('Processing ' + opportunity.Name);
                opportunity.NBType__c = null;
            }
            Database.SaveResult[] srList = database.update(scope, false); // allOrNone = false
            for (Integer i = 0; i < srList.size(); i++)
            if (!srList[i].isSuccess())
            this.log += '\n Error in Opportunity: ' + scope[i].name + '. Error msg=' +
            srList[i].getErrors()[0].getMessage();
        }
    }
}

dont miss out iconCheck out another amazing blog by Kirandeep here: Salesforce Apex Winter Release 21 - All You Need To Know

Responses

  1. Great information on How To Use a Database.Stateful Interface In Batch Apex In Salesforce. Very Insightful.

Popular Salesforce Blogs