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
tonantetonante 

Global Batch Class Variables set by Execute method are now Empty when verified in Finish Method

Hi,  If I define a global variable within  the global batch class that implements Batchable and then I update that variable in the global execute method. Why do the values for this global variable become null or empty when I try to use the variable in the global Finish method? The global variable in my case is a and object defined as List<Id> expireSoonList
and when I add values to this List of Ids and add a system debug file after the update - to show the size of this list - in method Execute , I get a non-zero value.
But when I check on the size of this list - by adding system.debug -  in the Finish method,  the global ID List is empty so I get a 0 shown for the system debug instruction . Here's the code snippet   Thanks much:
global class BatchMozoSubscriptionRenewObject implements Database.Batchable<sObject> {
    // global variables
	global List<Id> expireSoonList;
    global String query;
   global List<Id> Temp = new List<Id>();
    
    global String[] finishSubscriberEmailList;
    // Not a sandbox exception definition
	global class NotSandboxException extends Exception {} 
    
    
    global database.querylocator start(Database.BatchableContext BC)
    {
        if(query == null) 
        {
            query = 
                'Select Id, RecordType.Name, Status__c, ' 
                + 'Date_Inactive__c, Registration_Level__c ' 
                + 'From Account '
                + 'Where ( Status__c = \'Added\' and RecordType.Name in (\'Canada Church\' , \'US Organization\') ) ' 
           		+ 'And Registration_Level__c <> \'R0\' And Registration_Level__c <> null and Date_Inactive__c >= today';
        }
        
        system.debug('<<QUERY STRING>> '+query);
        
        return Database.getQueryLocator(query);
    }
    global void execute(Database.BatchableContext BC, List<sObject> scope)
    {
        
       	Integer currentMonth= 0;
        Integer expirationMonth = 0;
		Integer difference  = 0;
        date currentDate = date.today();
        for(sObject s : scope)
        {	           
            Account a = (Account)s;
            expirationMonth = (a.Date_Inactive__c).month();
            currentMonth = currentDate.month();
            system.debug('<<Expire Date>> '+a.Date_Inactive__c+' <<Current Date>> '+currentDate);
            //daysBetween(Date) Returns the number of days between the Date that called the method 
            //If Date that calls the method occurs after the futuer Date, return value is negative.
            Integer numberOfDaysBetween = currentDate.daysBetween(a.Date_Inactive__c);
            if(numberOfDaysBetween <= 30 & numberOfDaysBetween >= 0){
                expireSoonList.add(a.Id);
                //upsert expireSoonList;
                system.debug('<< EXECUTE ---> EXPIRE SOON LIST>> '+expireSoonList.size());
            }
         /*    
            if(currentDate <= a.Date_Inactive__c){
                
                if(currentMonth <= expirationMonth){
					difference = (expirationMonth - currentMonth);                   	
                }
                else{ // e.g. expiration month = January and current month = September
               		expirationMonth =  expirationMonth + 12;
					difference = (expirationMonth - currentMonth);                    	
               	} //ELSE
                // Check to see if we within 30 days
                if(difference <= 1){
                	if(currentDate.day() >= (a.Date_Inactive__c).day()){
                    	expireSoonList.add(a.Id);
                    }
                }   
          	}//IF
		*/
            
        }//FOR LOOp
        Temp = expireSoonList;
    }//Execute
    
   global void finish(Database.BatchableContext BC)
   {	system.debug('<<EXPIRE SOON LIST>> '+Temp.size());
       if(expireSoonList.size()> 0){
        	//Get Affiliation from Accounts in order to get the Affliated Ontacts who have Awana Roles that are COmmanders or Secretaries and that have email.
         	Map<Id,npe5__Affiliation__c> getContacts = new Map<Id,npe5__Affiliation__c>([Select Id,npe5__Contact__c from npe5__Affiliation__c where npe5__Organization__c in: expireSoonList and Awana_Role__c in ('Commander','Club Secretary')]); 
     		
            //Now extract the Contact  Emails into one list and send the email
     		List<Contact> mozoContacts = [Select Email from Contact where Email <> null and Id in: getContacts.keyset()];
        	
            //Now create a list of emails to send once. 
        	String emailList = '';
     		for(Contact c: mozoContacts){
             	emailList = emailList + c.Email+'\t';
        	}
       
           	String emails = emailList.replaceAll('[\t ]*','');
            //Since Email's setToAddress uses a List we need to convert it using tabs then commans
            List<String> finishEmailList = emails.split(',');
            Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();        
            mail.setToAddresses(finishEmailList);
            //mail.setReplyTo('tonyw@awana.org');
            mail.setSenderDisplayName('Mozo Subscription Renewal');
       		mail.setSubject('Mozo Subscription Renewal');
            mail.setPlainTextBody('Your subscription is about to expire within 30 days.\nPlease renew your subscription as soon as possible in order to maintain your Mozo registration. Thank you.\n');
                    
           	//send bulk email
            Messaging.SendEmailResult[] result = Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
            system.debug(result);
        }
    }
}

 
Best Answer chosen by tonante
tonantetonante
OK If any of you can solve this without my having to change  the code drastically that woul dbe great. However I think I have two solutions that could fix this issue:
1) Create a static varaible for the List <Id>
2) Just put the Finish method's code into Extecute method.
 
 I'll try one or both of these if solution 1 doesn't work thought I hope it does.

All Answers

tonantetonante
OK If any of you can solve this without my having to change  the code drastically that woul dbe great. However I think I have two solutions that could fix this issue:
1) Create a static varaible for the List <Id>
2) Just put the Finish method's code into Extecute method.
 
 I'll try one or both of these if solution 1 doesn't work thought I hope it does.
This was selected as the best answer
James LoghryJames Loghry
The correct way to do this is to have your batch class implement Database.Stateful.  See more here: http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_batch_interface.htm
Jorge EsparzaJorge Esparza
Ditto with James Loghry, Best Answer is incorrect. Using Database.Stateful interface on your batch class will solve the variable issue.
Email2Case UserEmail2Case User
If a normal apex calls this batch Apex then using stateful interface and global static variables in batch apex, can we access these global static variable in the calling normal apex.