1

Hi I am new in salesforce, and I want to create a Schedule Batch Apex that will query for any Contact and For each Contact returned create an Opportunity.

I have written the following code for this:

global class ScheduleContact implements Database.Batchable<SObject>
{
     List<contact> contactList;

     global Database.queryLocator start(Database.BatchableContext ctx)
     {
        contactList= new List<contact>([Select   Con.FirstName,Con.LastName,Con.AccountId,Con.Contract_End_Date__c  From contact con where Con.Payment_Type__c = 'Paid In Full' AND Con.Contract_End_Date__c >= LAST_N_DAYS:60]);
        return Database.getQueryLocator(contactList);

     }
     global void execute(Database.BatchableContext BC, List<contact> contactList )
     {
          //for creating new opportunity.
            List<Opportunity> newOpps=new List<Opportunity>();

            for(Contact c: contactList)
            {
                Opportunity opp=new Opportunity();
                opp.Name=c.FirstName+c.LastName+'Opportunity';
                opp.CloseDate=c.Contract_End_Date__c;
                opp.Type='Renewal';
                opp.StageName='Met';
                opp.AccountId=c.AccountId;
                newOpps.add(opp);
            }
            insert newOpps;
     }
     global void finish(Database.BatchableContext BC)
     {

     }
}

But it gives the following error:

Compile Error: Argument must be an inline query at line 8 column 16

which is in line

return Database.getQueryLocator(contactList);

Please tell me how to write code for such a problem can we write code for batch apex that returns list object as i do in above example.

  • 1
    Doing the query separately from the Database.getQueryLocator defeats the purpose of that method which is to circumvent the normal total records retrieved governor limit (presently 50,000) and raise the number of records that can be handled (presently 50 million). Hence the compile error pointing to the appropriate pattern. – Keith C Apr 9 '14 at 7:35
1

I rewrote your batch class to the way I write batch Apex - I hope this helps.

global class ScheduleContact implements Database.Batchable<SObject> {

global Database.queryLocator start(Database.BatchableContext ctx) {
    DateTime theDateTime = System.now().addDays(-60);
    String query = 'Select FirstName, LastName, AccountId, Contract_End_Date__c';
    query += ' FROM Contact WHERE Payment_Type__c = \'Paid In Full\'';
    query += ' AND Contract_End_Date__c >= :theDateTime';

    return Database.getQueryLocator(query);

}
global void execute(Database.BatchableContext BC, List<sObject> scope) {
    List<Contact> contactList = (List<Contact>)scope;

    //for creating new opportunity.
    List<Opportunity> newOpps = new List<Opportunity>();

    for (Contact c : contactList) {
        Opportunity opp = new Opportunity();
        opp.Name = c.FirstName + ' ' + c.LastName + ' Opportunity';
        opp.CloseDate = c.Contract_End_Date__c;
        opp.Type = 'Renewal';
        opp.StageName = 'Met';
        opp.AccountId = c.AccountId;
        newOpps.add(opp);
    }

    insert newOpps;
}
global void finish(Database.BatchableContext BC) {

}
}

I am using batchable, making a dynamic Apex query string, passing a list to the execute, casting it to a list and then working through that list to make new Opportunities.

(Edit: Thanks to @dphil for noticing my unused variable - removed it.)

|improve this answer|||||
  • 1
    You might want to get rid of that hanging private query variable you don't use. – dphil Apr 10 '14 at 20:36
  • 1
    ... and change the dynamic SOQL to static SOQL. – Keith C Apr 10 '14 at 20:48
  • 1
    @DavidSchach One of the few good features of Apex is that the compiler can process SOQL both in terms of flagging errors at compile time and eliminating the noise of string quotes. Seems like a lot to give up to me... (I think also the doc example is often to blame for dynamic SOQL being used.) – Keith C Apr 10 '14 at 21:47
  • 1
    @DavidSchach Database.getQueryLocator supports either type of argument e.g. salesforce.com/us/developer/docs/apexcode/Content/…. – Keith C Apr 11 '14 at 7:43
  • 1
    It surprised me too @DavidSchach. A SOQL literal [] passed into a Database.getQueryLocator does not evaluate to a list of sobjects, nor reduce the limit to 50,000. The Apex runtime parses it as a query definition or a delegate, giving both compile-time validation and up to 50,000,000 records. – bigassforce Apr 22 '14 at 15:59
0

Can you modify your start method as below

global class ScheduleContact implements Database.Batchable<SObject>
 {
     global Database.queryLocator start(Database.BatchableContext ctx)
     {
        return Database.getQueryLocator([Select Con.FirstName,Con.LastName,Con.AccountId,Con.Contract_End_Date__c From contact con where Con.Payment_Type__c = 'Paid In Full' AND Con.Contract_End_Date__c >= LAST_N_DAYS:60]);

     }
     global void execute(Database.BatchableContext BC, List<contact> contactList)
     {
          //for creating new opportunity.
            List<Opportunity> newOpps=new List<Opportunity>();

            for(Contact c: contactList)
            {
                Opportunity opp=new Opportunity();
                opp.Name=c.FirstName+c.LastName+'Opportunity';
                opp.CloseDate=c.Contract_End_Date__c;
                opp.Type='Renewal';
                opp.StageName='Met';
                opp.AccountId=c.AccountId;
                newOpps.add(opp);
            }
            insert newOpps;
     }
     global void finish(Database.BatchableContext BC)
     {

     }
}

Here I replaced your collection with the the query itself in the argument which Database.getQueryLocator() takes.

Hope it resolves your issue.

EDIT:I have updated the code including @keith's comment

|improve this answer|||||
  • ya I modified my start method as u said global Database.queryLocator start(Database.BatchableContext ctx) { return Database.getQueryLocator([Select Con.FirstName,Con.LastName,Con.AccountId,Con.Contract_End_Date__c From contact con where Con.Payment_Type__c = 'Paid In Full' AND Con.Contract_End_Date__c >= LAST_N_DAYS:60]); } after adding this code doesn't give any error but opportunity will not be created. tell me if we doesn't assign to the contactList How contact will store in that.Is there any method todo that. – user7717 Apr 9 '14 at 7:21
  • @user7717 Delete the line 3 contactList and make sure that your execute implementation uses the contactList passed to it as an argument. This will be a block of contacts returned from the start method of number equal to your batch size. – Keith C Apr 9 '14 at 8:02
-2

Since you want to pass a collection, you could use Iterable,

global Iterable<Contact> start(Database.BatchableContext BC) {
      contactList= new List<contact>([Select Con.FirstName,Con.LastName,Con.AccountId,Con.Contract_End_Date__c  From contact con where Con.Payment_Type__c = 'Paid In Full' AND Con.Contract_End_Date__c >= LAST_N_DAYS:60]);            
      return contactList;  
}
|improve this answer|||||
  • 1
    Could you not just link to a resource but explain why this is the answer ? – Samuel De Rycke Apr 9 '14 at 6:05
  • Thanks, i have taken your suggestion and edited my answer. – anmrk Apr 9 '14 at 6:21
  • 1
    I've downvoted this answer because using this pattern for the start method moves you back to the situation where the normal governor limit is enforced on the query in the start method which is typically what you don't want (unless that query is never a problem and the limit problem is in the execute). – Keith C Apr 9 '14 at 7:29
  • Ya I have change the code as u said But it gives error as "Error: Compile Error: ScheduleContact: Class must implement the global interface method: Iterable<SObject> start(Database.BatchableContext) from Database.Batchable<SObject> at line 1 column 14" tell me suggestion if any. – user7717 Apr 9 '14 at 7:29
  • i want to know,what and how if i want create Account record,,new account record,it will not associate with any childs – Satya Aug 3 '16 at 7:30

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.