Saturday, May 15, 2021

Database.Stateful in Batch Apex in Salesforce

Batch Apex is stateless. Each execution of a batch Apex job is considered a discrete transaction. If we implement a Database.Stateful, we can maintain state across transactions. Using Database.Stateful only instance variables hold values; static members do not hold values. If we want to count records as a batch proceeds, maintaining state is important, as after one transaction, a new transaction will start and members will lose their values.

Let's understand with an example,

The below batch class is querying all the accounts and their related contacts and updating the contact phone number with the account phone number. As we want to count the number of contacts updated using the batch class, we are implementing a Database.Stateful interface and finally sending mail to inform the user regarding the batch status.

public class UpdateContactPhone implements

    Database.Batchable<sObject>, Database.Stateful {

    public Integer recordsProcessed = 0;

    public Database.QueryLocator start(Database.BatchableContext bc) {

         String query = 'SELECT Id,Name,Phone,(SELECT id,Phone from Contacts) FROM Account';

        return Database.getQueryLocator(query);

    }

    public void execute(Database.BatchableContext bc, List<Account> scope){

        // process each batch of records

        List<Contact> contacts = new List<Contact>();

        for (Account account : scope) {

            for (Contact contact : account.contacts) {

                contact.phone= account.phone;

                contacts.add(contact);

                recordsProcessed = recordsProcessed + 1;

            }

        }

        update contacts;

    }

    public void finish(Database.BatchableContext bc){

        AsyncApexJob job = [SELECT Id, Status, NumberOfErrors,JobItemsProcessed, TotalJobItems, CreatedBy.Email FROM AsyncApexJob WHERE Id = :bc.getJobId()];

        // call some utility to send email

          Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();

        String[] toAddresses = new String[] {'Testabc@gmail.com'};

        mail.setToAddresses(toAddresses);

        mail.setSubject('Batch Status ' + job.Status + 'Record Processed ' + recordsProcessed );

        mail.setPlainTextBody('Total Jobs Processed: ' + job .TotalJobItems +   'with '+ job .NumberOfErrors + ' failures.');

        Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });

    }

}

Execute the above batch class from developer console as shown below,

UpdateContactPhone batchObject = new UpdateContactPhone ();
Id batchId = Database.executeBatch(batchObject);



1 comment:

  1. It is very awesome point of explanation with code example.

    ReplyDelete