I'm working on creating a batch which inserts a child record to accounts. The child record creation kicks off a separate process that relies on a lot of specific information being in place and is prone to failures, which we're trying to log on the accounts if the child record fails when its inserted. The partial success from AllOrNone being false doesn't seem to be working as expected, and when running more than a single record, if any fail at all the entire batch is updated to reflect the error. Example of the batch below (updated to be a bit more generic). Am is using the saveresult incorrectly or is there some other issue here? It works correctly when running 1 at a time.
global class Batch_CreateDunningInstance implements Database.Batchable<sObject>, Database.AllowsCallouts, Schedulable {
public Iterable<sObject> start(Database.BatchableContext bc) {
system.debug('start of Batch_CreateDunningInstance');
List<Account> scope = [SELECT Id, MS_Dunning_Profile__c
FROM Account
WHERE Create_Dunning_Cycle__c = true and Dunning_Criteria__c = true];
return scope;
}
global void execute(Database.BatchableContext BC, List<Account> scope) {
system.debug('entered execute of Batch_CreateDunningInstance');
List<Dunning_Instance__c> dunningInstancesToInsert = new List<Dunning_Instance__c>();
Map<Id, Account> accountsToUpdate = new Map<Id, Account>();
List<Account> accountsToUpdateList = new List<Account>();
for (Account acct : scope) {
Dunning_Instance__c di = new Dunning_Instance__C(
Account__c = acct.Id,
Dunning_Profile__c = acct.MS_Dunning_Profile__c
);
dunningInstancesToInsert.add(di);
accountsToUpdate.put(acct.Id, acct);
}
Database.SaveResult[] insertResults = Database.insert(dunningInstancesToInsert, false);
for (Integer i = 0; i < insertResults.size(); i++) {
Account acctToUpdate = accountsToUpdate.get(dunningInstancesToInsert[i].Account__c);
if (insertResults.get(i).isSuccess()) {
acctToUpdate.Create_Dunning_Cycle__c = false;
} else {
acctToUpdate.Dunning_Errors__c = insertResults[i].getErrors()[0].getMessage().trim();
}
accountsToUpdateList.add(acctToUpdate);
}
if(!accountsToUpdateList.isEmpty()) {
update accountsToUpdateList;
}
}
global void finish(Database.BatchableContext BC) {
}
global void execute(SchedulableContext sc) {
Database.executeBatch(new Batch_CreateDunningInstance(), 20);
}
}
execute
method. BTW, yourstart
method is poorly written; you should return aDatabase.QueryLocator
by simply returning the static or dynamic query wrapped inDatabase.getQueryLocator
. As it stands you actually execute the query, so this won't work with > 50K Accounts.