Running a Batch Job in Apex with mass records

March 5, 2012 § Leave a comment

A scenario comes when you need to process mass records either updating or inserting or deleting. We can make use of Batch Apex to process all the records at once.

Excerpts from the Force.com Winter ’10 Release :
Batch Apex gives you the ability to operate over large amounts of data by chunking the job into smaller parts, thereby keeping within the governor limits. Using batch Apex, you can build complex, long-running processes on the Force.com platform. For example, you could build an archiving solution that runs on a nightly basis, looking for records past a certain date and adding them to an archive. Or you could build a data cleansing operation that goes through all Accounts and Opportunities on a nightly basis and reassigns them if necessary, based on custom criteria.

In order to develop our Batch Apex, we need to create a new Apex class which extends “Database.Batchable” interface.

This interface will have three methods to be implemented:

  • start
  • execute
  • finish

“start” method is called at the beginning of a batch Apex job. Use this method to collect the records (of objects) to be passed to the “execute” method for processing. The Apex engine, automatically breaks the massive numbers of records you selected into smaller batches and repeatedly calls the “execute” method until all records are processed.

The “finish” method is called once all the batches are processed. You can use this method to carry out any post-processing operation such as sending out an email confirmation on the status of the batch operation.

Let’s take a closer look at each of these methods:
1. Start Method

global Database.QueryLocator start(Database.BatchableContext BC) {
      //passing the query string to the Database object.      
      return Database.getQueryLocator(query);
}

2. Execute method

 global void execute(Database.BatchableContext BC, List<sObject> scope){
    List<Account> accns = new List<Account>();

   for(sObject s : scope){Account a = (Account)s;
        if(a.OwnerId==fromUserId){
            a.OwnerId=toUserId;
            accns.add(a);
            }
        }
update accns;
}

3. Finish Method

global void finish(Database.BatchableContext BC){
  // Get the ID of the AsyncApexJob representing this batch job  
  // from Database.BatchableContext.    
  // Query the AsyncApexJob object to retrieve the current job's information.  

 AsyncApexJob a = [Select Id, Status, NumberOfErrors, JobItemsProcessed,
   TotalJobItems, CreatedBy.Email
   from AsyncApexJob where Id =:BC.getJobId()];

  // Send an email to the Apex job's submitter notifying of job completion.  
  Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
  String[] toAddresses = new String[] {a.CreatedBy.Email};
  mail.setToAddresses(toAddresses);
  mail.setSubject('Apex Sharing Recalculation ' + a.Status);
  mail.setPlainTextBody('The batch Apex job processed ' + a.TotalJobItems +
    ' batches with '+ a.NumberOfErrors + ' failures.');

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

Using the Inbound Email Service of Salesforce.com

November 2, 2011 § Leave a comment

If anybody has not come across this feature of Salesforce, then feel free to grok here as it is an out of the box functionality. This can help someone who needs to receive an email from outside of Salesforce and do something within Salesforce using an Apex class.

Just go to: Setup -> Develop -> Email Services.

Rest of the things are pretty straight forward. Click on “New Email Service” to create one. And then you can look up on Defining Email Services to fill in the details without much of an issue.

You would require an Apex Class to select for the field labeled as “Apex Class”. So, lets look at what you can do here:

global class ProcessEmail implements Messaging.InboundEmailHandler {
 
  global Messaging.InboundEmailResult handleInboundEmail(Messaging.InboundEmail email, Messaging.InboundEnvelope envelope) 
  {
 
    Messaging.InboundEmailResult result = new Messaging.InboundEmailresult();
 
    String str = email.plainTextbody;
    List parts = str.split('\n');
    String obj_name = parts[0];
    Id obj_Id = null;
    try{
        obj_Id = [Select id from Object__c where Name =: obj_name].Id;
        
        Attachment attachment = new Attachment();
        attachment.ParentId = obj_Id;
        attachment.Name = email.subject;
        attachment.Body = Blob.valueOf(email.htmlbody);
        attachment.ContentType = 'html';
        insert attachment;
    }catch(Exception qe){
  
        Messaging.reserveSingleEmailCapacity(2);
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();

        String[] toAddresses = new String[1];
        toAddresses[0] = email.fromAddress;
        
        System.debug('====&gt; to addresse '+toAddresses[0]); 

        mail.setToAddresses(toAddresses);
        mail.setReplyTo('mandeep.deka@mycompany.com');
        mail.setSenderDisplayName('App Support Administrator');
        mail.setSubject('App Support');
        mail.setBccSender(false);
        mail.setUseSignature(false);
        mail.setPlainTextBody('The Object: ' + obj_name  +' did not match with our app.');
        mail.setHtmlBody('Your Request to add your email as an attachment to the Object_Name:<b> ' + obj_name +' </b>has not been created.'+
             'A matching record could not be found in the app');

        Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
    }
       
    // Return the result for the Force.com Email Service
    return result;
 }
}

Here in the above class what we are doing is that we are reading the email sent from an anonymous address and trying to match the first line of the email with one of our Object record Name in Salesforce.com and based on that we attach the email body as an attachment to the respective Object record.

We also used a try and catch block to see if the Object record name matches with our record in Salesforce.com and if it doesn’t then we shoot back an email to the anonymous user based on the email address used to send the email to Salesforce.com.

Next, what we need to do is just add an Email address to publicize to those potential users who are going to send email to Salesforce.com i.e. to our app here.

If you have closed the Email Service window, better to open it and when you scroll down you will see a button to add “New Email Address”. Click on it and fill in the form using the help from this link Defining Email Service Addresses.

You just need to fill in the local part of the email address. Salesforce generates a unique domain-part for each email service address to ensure that no two email service addresses are identical. The generated domain-part appears to the right of the Email Address field.

One last thing that I would like to add here is that there might be a scenario when you might want to use the Email templates in Salesforce.com to use while reverting back to the anonymous user. In that case, take a look into this post Salesforce: Using basic email templates from Apex code.

One drawback of using Email Template is that the user sending the email cannot be anonymous anymore as he/she will have to be from either the Account, Contact or User because Email templates uses merge fields and there has be some access rights linked to the user who can view these fields if there are restricted sharing settings.

A few other links that might be helpful in using these service:

Where Am I?

You are currently browsing the Force.com category at Mandeep Deka.