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 protected]'};
    mail.setToAddresses(toAddresses);
    mail.setReplyTo('[email protected]');
    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.

1 Answer 1

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;

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .