1
public class UpdateBrandBatch implements Database.Batchable<sObject>, Database.Stateful {
    final List<SObject> records = new List<sObject>();
    final string query1, query2;

    public updateBrandBatch(){
        query1 = 'select id, brand__c from account';
        query2 = 'select id, brand__c from contact';
    }

    public Iterable<sObject> start(Database.BatchableContext BC) {   
        records.addAll(Database.query(query1));
        records.addAll(Database.query(query2));
        return records;
    }    

    public void execute(Database.BatchableContext BC, List<sObject> scope) {   
        for (sObject c : scope) {
            c.put('brand__c', 'MyBrand');
        }
        update scope;
    }    

    public void finish(Database.BatchableContext BC) { }   

}

Calling this batch from anonymous window using :

Database.executeBatch(new UpdateBrandBatch(), 20);

even though i enter batch size as 20, still getting the exception. There are some 20 million records of account and about 30 million contacts

Thanks

went through question # 60164 here in SOF and as per suggestion tried reducing the batch size but that didnt help.

  • 2
    @Himanshu I disagree. While I suspect this question may be duplicate, that question doesn't help answer this one. – sfdcfox Dec 16 '15 at 19:50
  • Hi @sfdcfox I am pointing this answer towards the "Modify your SOQL queries to be more selective and to only bring back the records required for the Contacts,Account in the scope. " – Himanshu Dec 16 '15 at 19:56
4

You can't query more than 50,000 rows in your start method. You need a QueryLocator. In practice, this probably means you'll need to run your batch twice, once by accounts and then once by contacts. Probably something like this:

public class ProcessRecords implements Database.Batchable<SObject> {
    public String[] queries = new String[] { 'select brand__c from account', 'select brand__c from contact' };
    public Database.QueryLocator start(Database.BatchableContext context) {
        return Database.getQueryLocator(queries.remove(0));
    }
    public void execute(Database.BatchableContext context, SObject[] records) {
    // Do processing here
    }
    public void finish(Database.BatchableContext context) {
       if(!queries.isEmpty()) {
          Database.executeBatch(this, 20);
       }
    }
}

For unit testing, you may need to call your methods directly instead of trying to execute the batches using Test.stopTest(), to avoid chaining errors.

  • Thanks sfdcfox. I was able to update brand on individual object using something like above you suggested. But I was asked to update the brand on multiple objects and looking for a common batch class to update everything. – sf_user Dec 16 '15 at 20:00
  • 2
    @pmvsdt As my code demonstrates, it is a common class that runs over both accounts and contacts. The point is, you need to run through twice-- once per sobject. – sfdcfox Dec 16 '15 at 20:06
  • Thanks sfdcfox. Will work on this and keep posted here but this sounds like a definite solution for me. Thankyou – sf_user Dec 16 '15 at 20:14
  • 1
    @javanoob No, we're not constructing a new class, so it retains the queries in the order they're defined. The only time you have to worry about the class not retaining changes is during the execute method. – sfdcfox Dec 17 '15 at 0:18
  • 1
    @pmvsdt You're welcome! I dedicate many hours a week to this site to help people, so this means a lot to me. I'm glad you found this useful. – sfdcfox Dec 18 '15 at 7:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.