function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Tim Jones 71Tim Jones 71 

In a Batchable Class Update the parent object form one of the scope records

Afternoon evryone,
Administrator making the move to developer so be easy on a rookie.
I have a class the implements Database.Batchable 
Start
In the start I am setting my scope with a SOQL query that gets all the members of a campaign where a logic check box is not set, scope
Execute
Now I am looping through those records and creating a new record in a form processor object that will be exposed in a public community for tokenized email responces
Loop through for cm :scope
Create a new form processeor record for each cm and add to list 
If the record count of list is >0 insert the list

Finish
Sending an email to the user letting them know the batch completed.

Problem
How can I check the logic box on the campaign after the member records are sent to batch

Code available if needed
AnudeepAnudeep (Salesforce Developers) 
Hi Tim,

Here is how you will check if an email is sent or not
 
List<Messaging.SendEmailResult> results = Messaging.SendEmail(new Messaging.Email[] { message });
            System.debug(results);
        if (!results.get(0).isSuccess()) {
            System.StatusCode statusCode = results.get(0).getErrors()[0].getStatusCode();
            String errorMessage = results.get(0).getErrors()[0].getMessage();

Posting a sample code here. You need to move the select checkbox logic to the finish method
 
global class UpdateContacts implements Database.Batchable<sObject>
{
    
   global Database.queryLocator start(Database.BatchableContext ctx )
   {
          
        String str = 'SELECT Id, checkbox__c FROM Contact WHERE checkbox__c = false';
        
        return Database.getQueryLocator(str);
        
   }
    
    global void execute(Database.BatchableContext ctx, List<Contact> contactToProcess)
     {
        
       List<Contact> contactList = new List<Contact>();
       
       for(Contact conObj : contactToProcess){
               checkbox__c = true;
            contactList.add(conObj);
          }
        
        update contactList;
     }
   
   global void finish(Database.BatchableContext ctx)
    {
   
      AsyncApexJob a = [SELECT Id, Status, NumberOfErrors, JobItemsProcessed,
                          TotalJobItems, CreatedBy.Email
                          FROM AsyncApexJob WHERE Id =
                          :ctx.getJobId()];
   // Send an email to the Apex job's submitter notifying of job completion. 
    
   Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
   String[] toAddresses = new String[] {a.CreatedBy.Email};
   mail.setToAddresses(toAddresses);
   mail.setSubject('Apex Sharing Recalculation ' + a.Status);
   mail.setPlainTextBody
   ('The batch Apex job processed ' + a.TotalJobItems +
   ' batches with '+ a.NumberOfErrors + ' failures.');
   Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
           
    }    
}
Tim Jones 71Tim Jones 71
Anudeep thanks for replying.
I did not explain it well. I am including my code to assist.
The problem I cannot solve, is this.
This batch executes on contact members of a campaign. It is triggered by a logic bolean on the campign record.
When the box is checked but the batch processed date is null, then the batch runs.
When the batch is finished, I need to populate the processed date on the campaign. 
I am successfully creating the batch, and sending the email when it is done.
What I am not able to do is populate the campaign record field processed date. 

So what it tried was to populate a string cId with the campaign id from the scope. That way in the finish, I could do an updated on that record
But whenever I try to extract the CampaignId from scope and assign it to Cid I get an error saying invalid list error. 
Once I get cId populated, I would just do a lookup on the campaign record, and update the processed date.
That value is stored in loop variable cm.CampaignId or in the scope CampaignId field
//Batch Class implemented on database.Batchable for an sobject defined in the start method

Global class batchCM implements Database.Batchable<SObject> {
    global string[] email = new String[] {'tj@life.com'};
    global String[] cId = new String[]{''};

/*  database.Batchable requires three methods, Start, Execute and Finish. This is the start method
    and it defines the scope of a batch based on a SOQL Query*/

    global Database.QueryLocator start(Database.BatchableContext BC){
    return Database.getQueryLocator('SELECT Id, CampaignId, ContactId, Campaign.Form_Process__c, Campaign.Form_Process_Date__c FROM CampaignMember Where Campaign.Form_Process__c = True AND Campaign.Form_Process_Date__c = null');
}

/*  The second required database.Batchable method is execute, where the work is done
    in this case we are for looping through the scope records and creating new community form
    records for each scope campaign member record*/

    global void execute(Database.BatchableContext BC,List<CampaignMember> scope){
    List<Community_Form__c> newFormList = new List<Community_Form__c>();
    for(CampaignMember cm : scope){
    Community_Form__c cform = new Community_Form__c(CM_Id__c=cm.Id,
                                                    Contact__c=cm.ContactId,
                                                    Campaign__c=cm.CampaignId,
                                                    Status__c='New',
                                                    Date__c=system.today(),
                                                    Type__c='CM',
                                                    Active__c=true,
                                                    Comment__c='Created from Apex Batch');
    newFormList.add(cform);
    }
    if(newFormList != null && newFormList.size()>0) {
        Database.insert(newFormList);
// left off here did not work        cId=String.valueOf(cm.CampaignId);    
    }
}

/*  Thhe final method is the finsh mehtod that should be sending an email to me saysing the batch is done
    but this is not working at the momeent
    To Do 
    Replace formulas on form object to contact and replace with static fileds updted in the batch
    Add the update on the campaign to populate the procesed date
    look at the flow to see if we can switch between smaller campaigns to run from the flow vs batch on larger campaigns
    */

global void Finish(Database.BatchableContext BC){

    Messaging.SingleEmailMessage mail=New Messaging.SingleEmailMessage();
    AsyncApexJob a =[select a.CompletedDate,a.JobItemsProcessed,a.NumberOfErrors,a.TotalJobItems, a.Status From AsyncApexJob a where id=:BC.getJobId()];
    mail.setToAddresses(email);
    mail.setReplyTo('tj@life.com');
    mail.setSenderDisplayName('Apex Batch Job');
    mail.setSubject('batch processing ' + a.Status);
    mail.setPlainTextBody('Job is done Records processed' + a.TotalJobItems
                        +' Number of errors '+ a.NumberOfErrors
                        +' Status '+a.Status
                        +'Job Items Processed '+ a.JobItemsProcessed
                        +'Completed '+ a.CompletedDate);
    Messaging.sendEmail(new Messaging.SingleEmailMessage[]{mail});
    }
}

 
Tim Jones 71Tim Jones 71
I have it working, Not sure this is the best way, and ideas on how to improve the code would be appreciated. To solve the problem I added 
this to the Finish Method
List<Campaign> campup = [SELECT Id, Form_Process__c, Form_Process_Date__c FROM Campaign Where Form_Process_Date__c = null and Form_Process__c =True Limit 1];
    Campaign pcamp = campup[0];
        pcamp.Form_Process_Date__c = system.today();
    update pcamp;