I'm trying to figure out how best to modify an existing Apex class to implement the Database.Batchable interface. I currently have two classes:
CustomerInfoUpdater - this class is void and is currently a Scheduled Job in our Sandbox via the "Schedule Apex" gui screen. The logic performs a MAX function to get the highest value in the Latest_Year_of_Training__c field on the contact object, and then update the corresponding customer info record with the same AccountId. There are two objects that are both master-detail to an Account that are used in this class: Contacts - standard JBCXM__CustomerInfo__c - this is a custom object that is used in a 3rd party system. Account records have 1 customer info record, and contains summary level detail for a given account. ScheduleCustomerInfoUpdater - this is a utility class that sets up CustomerInfoUpdater as a scheduled job. The CRON details are not in this class - I'd like to have the schedule set in the Scheduled Jobs gui in Salesforce. It came to my attention that since I'm dealing with bulk records it makes the most sense to use the Database.Batchable interface, which will also make it easier to develop a test class. I understand that Database.Batchable requires the 3 methods of start, execute, and finish, but I'm uncertain how to take my existing code and align it to the requirements of the interface.
Can someone please take a look at my existing code and recommend what would need to be done in order to implement Database.Batchable? Any help is greatly appreciated.
public class CustomerInfoUpdater {
public static void updateTrainingYear() {
// get full list of contacts who have attended training sessions
List < AggregateResult > attendeeAccounts = [SELECT AccountId, MAX(Latest_Year_of_Training_Attended__c) FROM Contact WHERE Latest_Year_of_Training_Attended__c != NULL GROUP BY AccountId];
System.debug('There are ' + attendeeAccounts.size() + ' accounts in the list.');
// parse the attendeeAccounts aggregate result into a usable map
Map < Id, Double > accountTrainingYear = new Map < Id, DOUBLE > ();
for (AggregateResult aR: attendeeAccounts) {
accountTrainingYear.put((ID) aR.get('AccountId'), (DOUBLE) aR.get('expr0'));
}
System.debug(accountTrainingYear.values());
// get all customer info records where the account IDs match
List < JBCXM__CustomerInfo__c > customerInfoList = [SELECT Id,
JBCXM__Account__c,
Product_Training_Attendance__c
FROM JBCXM__CustomerInfo__c
WHERE JBCXM__Account__c IN: accountTrainingYear.keySet()
];
System.debug('There are ' + customerInfoList.size() + ' customer info records in the list.');
// holding list for records to update
List < JBCXM__CustomerInfo__c > customerInfoUpdateList = new List < JBCXM__CustomerInfo__c > ();
// iterate through the list of customer info records and set the product training year
for (JBCXM__CustomerInfo__c cI: customerInfoList) {
cI.Product_Training_Attendance__c = accountTrainingYear.get(cI.JBCXM__Account__c);
System.debug('Setting Customer Info Record: ' + cI.Id + ' against AccountId: ' + cI.JBCXM__Account__c + 'to ' + accountTrainingYear.get(cI.JBCXM__Account__c));
customerInfoUpdateList.add(cI);
}
// DML update to adjust customer info records
update customerInfoUpdateList;
}
}
global class scheduleCustomerInfoUpdater implements Schedulable {
global void execute(SchedulableContext SC) {
CustomerInfoUpdater.updateTrainingYear();
}
}