3

I am writing a batch method for a client that just updates a couple of field based on the date. I used this example as a guide.

Here's my code:

global class BatchUpdateFiscalMonth implements Database.Batchable<SObject>, Database.Stateful{

Double failedUpdates{get; set;}

global BatchUpdateFiscalMonth(){
    failedUpdates = 0;
}

global Database.queryLocator start(Database.BatchableContext ctx){
    return Database.getQueryLocator([SELECT id, Current_Fiscal_Month__c, Current_Fiscal_Month_Value__c, Invoice_Date__c, ACK_Date__c, Fiscal_Month_Text__c, RecordType.Id FROM Invoice_Order__c]);
}

global void execute(Database.BatchableContext ctx, List<Sobject> scope){

    RecordType invoiceType = [SELECT id FROM RecordType WHERE sObjectType = 'Invoice_Order__c' AND Name = 'Invoice'];
    RecordType orderType = [SELECT id FROM RecordType WHERE sObjectType = 'Invoice_Order__c' AND Name = 'Order'];

    List<Invoice_Order__c> invOrds = (List<Invoice_Order__c>)scope;

    for(Integer i = 0; i < invOrds.size(); i++){
        invOrds[i].Current_Fiscal_Month_Value__c = String.valueOf(fiscalMonths.getCurrentFiscalMonth());
        if(invOrds[i].RecordType.Id == invoiceType.id){
            invOrds[i].Fiscal_Month_Text__c = String.valueOf(fiscalMonths.getFiscalMonth(invOrds[i].Invoice_Date__c));
        }
        if(invOrds[i].RecordType.Id == orderType.id){
            invOrds[i].Fiscal_Month_Text__c = String.valueOf(fiscalMonths.getFiscalMonth(invOrds[i].ACK_Date__c));
        }
    }       

    List<Database.saveResult> dsrs = Database.update(invOrds, false);
    for(Database.SaveResult dsr : dsrs){
        if(!dsr.isSuccess()){
            failedUpdates++;
        }
    }
}

global void finish(Database.BatchableContext ctx){

    AsyncApexJob a = [SELECT id, ApexClassId, 
                    JobItemsProcessed, TotalJobItems, 
                    NumberOfErrors, CreatedBy.Email
                    FROM AsyncApexJob
                    WHERE id = :ctx.getJobId()];

    String emailMessage = 'Your batch job '
         + 'BatchUpdateFiscalMonth '
         + 'has finished. It executed '
         + a.totalJobItems
         + ' batches. Of which, ' + a.jobitemsprocessed
         + ' processed without any exceptoins thrown and '
         + a.numberOfErrors
         + ' batches threw unhandled exceptions.'
         + ' Of the batches that executed without error, '
         + failedUpdates
         + ' records were not updated successfully.';
    Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
    String[] toAddresses = new String[] {'email@domain.com'};
    mail.setToAddresses(toAddresses);
    mail.setReplyTo('noreply@salesforce.com');
    mail.setSubject('Batch job completed');
    mail.setPlainTextBody(emailMessage);
    mail.setHtmlBody(emailMessage);
    Messaging.sendEmail(new Messaging.SingleEmailMessage[]{ mail });
}

public static testMethod void TestBatchUpdateFiscalMonth(){

    //create the test data
    RecordType invoiceType = [SELECT Id FROM RecordType WHERE sObjectType = 'Invoice_Order__c' AND Name = 'Invoice'];
    RecordType orderType = [SELECT Id FROM RecordType WHERE sObjectType = 'Invoice_Order__c' AND Name = 'Order'];

    Account testAccount = new Account(Name='Test');
    insert testAccount;

    List<Invoice_Order__c> invoices = new List<Invoice_Order__c>();
    List<Invoice_Order__c> orders = new List<Invoice_Order__c>();

    for(Integer i=0;i<10;i++){
        Invoice_Order__c inv = new Invoice_Order__c(RecordType=invoiceType,Invoice_Date__c=Date.Today(),Account__c=testAccount.Id);
        invoices.add(inv);

        Invoice_Order__c ord = new Invoice_Order__c(RecordType=orderType,ACK_Date__c=Date.Today(),Account__c=testAccount.Id);
        orders.add(ord);
    }
    insert invoices;
    insert orders;

    // do the test
    Test.startTest();
    Database.executeBatch(new BatchUpdateFiscalMonth());
    Test.stopTest();

    // Verify the test results
    invoices = [SELECT Invoice_Date__c, Current_Fiscal_Month_Value__c,Fiscal_Month_Text__c FROM Invoice_Order__c WHERE Id IN :invoices];
    for(Invoice_Order__c io: invoices){
        System.assertEquals(io.Fiscal_Month_Text__c,String.valueOf(fiscalMonths.getFiscalMonth(io.Invoice_Date__c)));
        System.assertEquals(io.Current_Fiscal_Month_Value__c,String.valueOf(fiscalMonths.getCurrentFiscalMonth()));
    }
    orders = [SELECT ACK_Date__c,Fiscal_Month_Text__c, Current_Fiscal_Month_Value__c FROM Invoice_Order__c WHERE Id IN :orders];
    for(Invoice_Order__c io: orders){
        System.assertEquals(io.Current_Fiscal_Month_Value__c,String.valueOf(fiscalMonths.getCurrentFiscalMonth()));
        System.assertEquals(io.Fiscal_Month_Text__c,String.valueOf(fiscalMonths.getFiscalMonth(io.ACK_Date__c)),io.ACK_Date__c);
    }
}

}

I have tried running the statements in the APEX execute anonymous window, and they all succeed done that way. Every time it results in an email message that says:

Your batch job BatchUpdateFiscalMonth has finished. It executed 1 batches. Of which, 1 processed without any exceptoins thrown and 0 batches threw unhandled exceptions. Of the batches that executed without error, 2.0 records were not updated successfully.

There was nothing in the logs that was helpful. I don't know how to diagnose this. I'm at a total loss here.

5

You are successfully getting to the update DML operation so all you need to do is view the errors from your saveResult. There are two ways to do this:

1) View the error messages in the debug log by system.debugging them. Note that the debug logs for the batch job are separate from the anonymous apex since it executes in a separate context.

2) Put the error messages in a string just like the number of failed records are being tracked and add that as part of your message in the finish task.

Double failedUpdates{get; set;}
String errorMessages {get; set;}
...
    for(Database.SaveResult dsr : dsrs){
        if(!dsr.isSuccess()){
            failedUpdates++;
            //the following is only ok since you have such a small batch size. If you leave this in the production code there might be heap size and speed problems.
            errorMessages += string.valueof(dsr.geterrors() + '\n'); 
            system.debug('Error Messages: '+dsr.geterrors());
        }
    }
...
         + ' Of the batches that executed without error, '
         + failedUpdates
         + ' records were not updated successfully.';
         + 'errors: ' + errorMessages;

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.