I have a scenario where I have to create 30000 contacts and 15,000 accounts (i.e. 2 contacts per account) in an org. I have been trying to do this by using batch apex but I still have error of "First error: Too many DML rows: 10001". Is there any way of overcoming this..? I have done a little research into using Iterator with batch class but not quite sure how this works. Here is what I have attempted so far:
global class performDML implements Database.Batchable<sObject>, Database.Stateful {
PRIVATE STATIC FINAL BOOLEAN LOG_THIS_CLASS = TRUE;
global Database.QueryLocator start(Database.BatchableContext BC){
if (LOG_THIS_CLASS) System.debug('in start');
insertAccountsAndContacts();
String query = 'SELECT id, isDeleted FROM Account WHERE isDeleted = false';
if(test.isRunningTest()){
query += ' LIMIT 10';
}
return Database.getQueryLocator(query); //Dummy query
}
global void execute(Database.BatchableContext BC, list<SObject> sc){
if (LOG_THIS_CLASS) System.debug('in execute');
performUpdate();
}
global void finish(Database.BatchableContext BC){
}
global static void insertAccountsAndContacts(){
if (LOG_THIS_CLASS) System.debug('in insertAccountsAndContacts()');
String accountName = 'Dummy Account ';
String contactName = 'Dummy Contact ';
List<Account> accountList = new List<Account>();
List<Contact> contactList = new List<Contact>();
Account acc;
Contact con;
Integer accountLoopSize = 15000;
Integer contactLoopSize = 30000;
for (Integer i = 0; i < accountLoopSize; i++){
acc = new Account(Name = accountName + i);
accountList.add(acc);
}
for (Integer j = 0; j < contactLoopSize; j++){
con = new Contact(LastName = contactName + j);
contactList.add(con);
}
insert accountList;
insert contactList;
}
global static void performUpdate(){
if (LOG_THIS_CLASS) System.debug('in performUpdate()');
List<Contact> contactList = [SELECT Id, LastName FROM Contact WHERE LastName LIKE 'Dummy%'];
List<Account> accountList = [SELECT Id, Name FROM Account WHERE Name LIKE 'Dummy%'];
List<Contact> contactListToUpdate = new List<Contact>();
Integer count;
for(Contact cons : contactList){
count = 0;
for(Account accs : accountList){
cons.AccountId = accs.Id;
contactListToUpdate.add(cons);
count ++;
if (count == 2) break;
}
}
update contactListToUpdate;
}
}
and I call this by:
performDML b = new performDML();
Database.executeBatch(b, 200);
Any help is much appreciated.
Thanks
Best Answer
So as written, that doesn't really operate as a batch should - the batch just calls the one method and tries to create all the records in one execution...a batch is designed to run as a series of iterations. I think what you need is a batch that uses a custom iterator - so take a look at this StackEx post. In that example, they use a String Iterator, but I think you need to use an Integer Iterator, or maybe main state and keep count.
Essentially, you need the batch to only create ~200 accounts per execution to stay within the limits
Here's a better formatted version of SFDCFox's example:
*****Edit***** And then the batch would look something like this: