I have batch class that I'm using to add Contacts to a Campaign. I could have up to 6000 contacts I need to add at one time. I'm calling the batch from another controller class.
Question is for batch apex do list work the same way as updating a record or inserting a record. Let's say in the batch execute I add the members to a list and then insert the list. Will Apex break up that list and add members via the scope (I have it as 1000). Here is the code I have for the batch. It works fine in the Sandbox, but I'm only working with a few contacts.
UPDATED CODE
Batch Class
global class BatchAddToCampaign implements Database.Batchable<sObject>, Database.Stateful
{
Id campaignId {get; set;}
Set<Id> qKeys {get; set;}
global BatchAddToCampaign(Id campaignId, Set<Id> qKeys){
this.campaignId = campaignId;
this.qKeys = qKeys;
}
global Database.QueryLocator start(Database.BatchableContext BC)
{
return Database.getQueryLocator('Select Id, Name, AccountId, Email From Contact Where Id In :qKeys');
}
global void execute(Database.BatchableContext BC, List<Contact> scope)
{
List<CampaignMember> cm = new List<CampaignMember>();
for(Contact c : scope)
{
CampaignMember newCM = new CampaignMember(
CampaignId = campaignId,
ContactId = c.Id,
status = 'Sent' );
cm.add(newCM);
}
try {
Database.insert(cm);
} catch (Exception ex) {
System.Debug('Insert failed ' + ex);
}
}
global void finish(Database.BatchableContext BC)
{
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('Add to Campaign ' + a.Status);
String campaignURL = URL.getSalesforceBaseUrl().toExternalForm() + '/' + campaignId;
mail.setPlainTextBody('The batch Apex job processed ' + a.TotalJobItems + ' batches with '+ a.NumberOfErrors + ' failures. '
+ 'Link to Campaign: ' + campaignURL);
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}
}
Test Class
@isTest
private class TestSupportBatchCampaign {
static testMethod void testBatchCampaign() {
Account a = new Account(Name='Support');
insert a;
Contact c = new Contact(AccountID = a.Id, FirstName = 'TestFirst', LastName='TestLast', Email='[email protected]');
insert c;
Map<Id, Contact> conMap = new Map<Id, Contact>([Select Id, Name, Email From Contact Where Id = :c.id]);
Campaign cp = new Campaign(Name='SupportBatchTestCampaign', Goal__c='Exposure');
insert cp;
Set<Id> qKeys = conMap.keyset();
Id campaignId = cp.Id;
List<CampaignMember> cm = new List<CampaignMember>();
List<Contact> cList = new List<Contact>();
cList.add(c);
for(Contact con : cList)
{
CampaignMember newCM = new CampaignMember(
CampaignId = campaignId,
ContactId = c.Id,
status = 'Sent' );
cm.add(newCM);
}
Database.insert(cm);
Test.startTest();
Id batchId = Database.executeBatch(new BatchAddToCampaign(campaignId, qKeys));
AsyncApexJob aj = [SELECT Id, Status, CreatedBy.Email FROM AsyncApexJob WHERE Id = :batchId];
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
String[] toAddresses = new String[] {aj.CreatedBy.Email};
mail.setToAddresses(toAddresses);
mail.setSubject('test');
mail.setPlainTextBody('test');
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
Test.stopTest();
}
}
insert cm
with Database.insert with support for partial successes so no one record blows up the 1000 records due to a validation error