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
sfdc dev 2264sfdc dev 2264 

converting a trigger /class to a batch class help needed

Hi,

I am having a trigger referred in a class which works fine , but fails in some cases , I would like to convert that class to a batch class and use it in my trigger

Kindly help me pls

 
MY TRIGGER CODE:

trigger ContractTrigger on Contract__c(After Update,After Insert) {    
    try{
        Trigger_Status__c ts = Trigger_Status__c.getValues('ContractTrigger');
        if(ts.Active__c){
            
            if(Trigger.isUpdate){

                TravelFundHandler.ValidateContractTermination(Trigger.New,Trigger.oldMap);
                ContractTriggerHandler.ContractfieldsupdateonAccount(Trigger.New, Trigger.oldMap);
                ContractTriggerHandler.contractcommencementdate(Trigger.New, Trigger.oldMap);
                ContractTriggerHandler.contractexpirydate(Trigger.New, Trigger.oldMap);
                 
            }  
            if(Trigger.isInsert){

                
                TravelFundHandler.travelFundMethod(Trigger.New,Trigger.oldMap);
              
            } 
            if(Trigger.isUpdate && TravelFundHandler.firstRun){
                TravelFundHandler.firstRun=false;
                TravelFundHandler.SignOnMethod(Trigger.New,Trigger.oldMap);
                
            }
          
           
            
        }
        
    }catch(Exception e){
        System.debug('Error Occured From Contract Trigger: '+e.getMessage());
    }
}
 
MY CLASS CODE :



public class triggerhandler{   
  
     
       public static void ContractfieldsupdateonAccount(List<Contract__c> newList, Map<Id, Contract__c> oldMap){
         
            Map<Id, Date> accMaptomaxcontractenddate = new Map<Id, Date>();
            Set<Id> accIds = new Set<Id>();
            List<Account> updateAcccontinfo = new List<Account>();
            Date d;
                
                        //Collecting the Account information from the Contract where the Status is 'Signed by Customer'
                        
                        for(Contract__c contr: newList){
        
                  if(contr.Status__c == 'Signed by Customer') 
                
                accIds.add(contr.Account__c);
                
                  System.debug('Account Ids: '+accIds);

                AggregateResult[] groupedResults = [SELECT Id,Account__c,MAX(Contract_End_Date__c)  
  FROM Contract__c where Account__c IN :accIds and Contracted__c = TRUE group by Account__c,Id ORDER BY MAX(Contract_End_Date__c) DESC NULLS LAST LIMIT 1]; 
                     // To get the Maximum contract end date of the Active (End Date > Today > Start date) Contract
            
                     for(AggregateResult ar :groupedResults){
  
  d = (Date)ar.get('expr0');
 System.debug('Maximum Contract End date: '+d);
  accMaptomaxcontractenddate.put((Id)ar.get('Account__c'),(Date)ar.get('expr0'));
  System.debug('Accmap for contracted Maximum Contract End date: : '+accMaptomaxcontractenddate);
  }
                   // To get the Account information associated to the Maximum contract end date of the Active (End Date > Today > Start date) Contract 
                   Map<id,Account> accMaptocontractfields = new Map<id,Account>();
            
                    
                   accMaptocontractfields = new Map<Id, Account>([SELECT Id, Contract_Start_Date__c, Contract_End_Date__c, Contract_Commencement_Date__c, 
                   Contract_Expiry_Date__c, No_of_Contracts__c,Qantas_Annual_Expenditure__c,Contract_Term_in_Months__c,Domestic_Annual_Share__c, International_Annual_Share__c,
                   Unit_Spend_per_term__c, Contracted__c,(SELECT Id, Contract_Start_Date__c, Contracted__c, Contract_End_Date__c, 
                   Domestic_Annual_Share__c, International_Annual_Share__c, Type__c,Qantas_Annual_Expenditure__c,Contract_Term_in_Months__c,
                   Unit_Spend_per_term__c  FROM Contracts__r where (Contract_End_Date__c = :d AND Contracted__c = TRUE) ORDER BY CreatedDate DESC NULLS LAST limit 1 ) FROM Account where Id IN : accIds ]);
                   
                  System.debug('Account map for contract end date:'+accMaptocontractfields);
                    
                     // To get the Contract associated to the Account from the map mentioned above
                  
                  Account acco = accMaptocontractfields.get(contr.Account__c);
                    
                             Date startDate,endDate;
                             Decimal domShare, intShare, unitspend,qantasannual,term;
                             String type;
                             Boolean contracted = false;
                    
                      for(Contract__c contr1 : acco.Contracts__r){
                          
                                  
                                   if(startDate == null && endDate == null){
                                        
                                        startDate = contr1.Contract_Start_Date__c;
                                        endDate = contr1.Contract_End_Date__c;
                                        domShare = contr1.Domestic_Annual_Share__c;
                                        intShare = contr1.International_Annual_Share__c;
                                        unitspend = contr1.Unit_Spend_per_term__c;
                                        qantasannual = contr1.Qantas_Annual_Expenditure__c;
                                        type = contr1.Type__c;
                                        term = contr1.Contract_Term_in_Months__c;
                                        contracted = contr1.Contracted__c;
                                        
                                    }else if(startDate.daysBetween(endDate) < contr1.Contract_Start_Date__c.daysBetween(contr1.Contract_End_Date__c)){
                                        
                                        startDate = contr1.Contract_Start_Date__c;
                                        endDate = contr1.Contract_End_Date__c;
                                        domShare = contr1.Domestic_Annual_Share__c;
                                        intShare = contr1.International_Annual_Share__c;
                                        unitspend = contr1.Unit_Spend_per_term__c;
                                        qantasannual = contr1.Qantas_Annual_Expenditure__c;
                                        type = contr1.Type__c;
                                        term = contr1.Contract_Term_in_Months__c;
                                        contracted = contr1.Contracted__c;
                                    }                                
                                 
                             }
                             
                    //Setting the Highest end date Active Contract information on Account 
                 
                    acco.Contract_Start_Date__c = startDate;
                    acco.Contract_End_Date__c = endDate;
                    acco.Domestic_Annual_Share__c =  domShare;
                    acco.International_Annual_Share__c = intShare;
                    acco.Type__c = type  ;
                    acco.Qantas_Annual_Expenditure__c = qantasannual;
                    acco.Contract_Term_in_Months__c =  term;
                    acco.Unit_Spend_per_term__c = unitspend;
                    acco.Contracted__c =    contracted;
                    
                    
                    System.debug('Account Contract Start Date: '+  acco.Contract_Start_Date__c );
                    System.debug('Account Contract End date: '+acco.Contract_End_Date__c);
                    System.debug('Contract Term in Months: '+acco.Contract_Term_in_Months__c);
                    System.debug('Units spend per term: '+acco.Unit_Spend_per_term__c);
                    System.debug('Account Contract Category: '+acco.Type__c);
                    System.debug('Forecast QF Spend: '  +acco.Qantas_Annual_Expenditure__c);
                    System.debug('Forecast QF Share (Dom) [System]: '+acco.Domestic_Annual_Share__c);
                    System.debug('Forecast QF Share (Int) [System]: '+acco.International_Annual_Share__c);
                    System.debug('Contracted:'+acco.Contracted__c);
                    
                      updateAcccontinfo.add(acco);
                    }

         
                    
            try{
          
            Database.SaveResult[] srlist = Database.Update(updateAcccontinfo, false);
                for (Database.SaveResult sr : srlist){
if (!sr.isSuccess()) {
    
    // Updation failed due to duplicate detected
    for(Database.Error duplicateError : sr.getErrors()){
        Datacloud.DuplicateResult duplicateResult = 
                  ((Database.DuplicateError)duplicateError).getDuplicateResult();
        System.debug('Duplicate records have been detected by ' + 
                  duplicateResult.getDuplicateRule());
        System.debug(duplicateResult.getErrorMessage());
    }

    // If the duplicate rule is an alert rule, we can try to bypass it
    Database.DMLOptions dml = new Database.DMLOptions(); 
    dml.DuplicateRuleHeader.AllowSave = true;
    Database.SaveResult[] sr2list = Database.Update(updateAcccontinfo, dml);
     for (Database.SaveResult sr2 : sr2list){
    if (sr2.isSuccess()) {
        System.debug('Duplicate account has been updated in Salesforce!');
    }
}
}
}
            }

catch(Exception e){
               System.debug(' Exception Occured: '+e.getMessage());
               }
        }
        
        /* This method is being used to populate the Account fields "Contract Commencement Date" of the 
      Minimum contract start date with the status "Signed by Customer" */
        
        public static void contractcommencementdate(List<Contract__c> newList, Map<Id, Contract__c> oldMap){
           
            Map<Id, Date> accMaptomincontractstartdate = new Map<Id, Date>();
            Set<Id> accoIds = new Set<Id>();
            List<Account> updateAcccommdate = new List<Account>();
            Date d;
            Date commencementDate;
            
            //Collecting the Account information from the Contract where the Status is 'Signed by Customer'
        
         for(Contract__c contr: newList){
           
         if(contr.Status__c == 'Signed by Customer' ) 
                
            accoIds.add(contr.Account__c);
    
             // To get the Minimum contract start date of the ""Signed by Customer" Contract    
             
            AggregateResult[] groupedResults = [SELECT Id,Account__c, MIN(Contract_Start_Date__c)  
  FROM Contract__c where Account__c IN :accoIds and Status__c = 'Signed by Customer' group by Account__c,Id ORDER BY MIN(Contract_Start_Date__c) ASC NULLS LAST LIMIT 1];
          
  for(AggregateResult ar : groupedResults){
      accMaptomincontractstartdate.put((Id)ar.get('Account__c'),(Date)ar.get('expr0'));
      
      System.debug('Accmap for Minimum Contract Start date: : '+accMaptomincontractstartdate);
      d=(Date)ar.get('expr0');
      System.debug('Least Commencement Date: '+d);
     }
                 
                 // To get the Account information associated to the Minimum contract start date of the "Signed by Customer" Contract
                 Map<id,Account> accMaptocommencementdate = new Map<id,Account>();
     
                     accMaptocommencementdate = new Map<Id, Account>([SELECT Id, Contract_Start_Date__c, Contract_End_Date__c, Contract_Commencement_Date__c, 
                   Contract_Expiry_Date__c, No_of_Contracts__c,Qantas_Annual_Expenditure__c,Contract_Term_in_Months__c,Domestic_Annual_Share__c, International_Annual_Share__c,
                   Unit_Spend_per_term__c, Contracted__c,(SELECT Id, Contract_Start_Date__c, Contracted__c, Contract_End_Date__c, 
                   Domestic_Annual_Share__c, International_Annual_Share__c, Type__c,Qantas_Annual_Expenditure__c,Contract_Term_in_Months__c,
                   Unit_Spend_per_term__c  FROM Contracts__r where (Contract_Start_Date__c = :d and Status__c = 'Signed by Customer')limit 1 ) FROM Account where Id IN : accoIds]);
  
   
               // To get the Contract associated to the Account from the map mentioned above
   Account accou = accMaptocommencementdate.get(contr.Account__c);
  
  for(Contract__c contr2 : accou.Contracts__r){
  commencementDate = contr2.Contract_Start_Date__c;
  }
  
  //Setting the Minimum Contract start date to the Account Contract commencement date
 
 accou.Contract_Commencement_Date__c =  commencementDate;
 
 System.debug('Account Contract Commenecement Date:'+accou.Contract_Commencement_Date__c);
     updateAcccommdate.add(accou);
      }
           
 
     
        
            try{
          
            Database.SaveResult[] srlist = Database.Update(updateAcccommdate, false);
                for (Database.SaveResult sr : srlist){
if (!sr.isSuccess()) {
    
    // Updation failed due to duplicate detected
    for(Database.Error duplicateError : sr.getErrors()){
        Datacloud.DuplicateResult duplicateResult = 
                  ((Database.DuplicateError)duplicateError).getDuplicateResult();
        System.debug('Duplicate records have been detected by ' + 
                  duplicateResult.getDuplicateRule());
        System.debug(duplicateResult.getErrorMessage());
    }

    // If the duplicate rule is an alert rule, we can try to bypass it
    Database.DMLOptions dml = new Database.DMLOptions(); 
    dml.DuplicateRuleHeader.AllowSave = true;
    Database.SaveResult[] sr2list = Database.Update(updateAcccommdate, dml);
     for (Database.SaveResult sr2 : sr2list){
    if (sr2.isSuccess()) {
        System.debug('Duplicate account has been updated in Salesforce!');
    }
}
}
}
            }

catch(Exception e){
               System.debug(' Exception Occured: '+e.getMessage());
               }
        }
        
        
         public static void contractexpirydate(List<Contract__c> newList, Map<Id, Contract__c> oldMap){
         
          Map<Id, Date> accMaptomaxcontractexpdate = new Map<Id, Date>();
          Set<Id> accIds = new Set<Id>();
          List<Account> updateAccexpdate = new List<Account>();
          Date d;
          Date expiryDate;
        
                //Collecting the Account information from the Contract where the Status is 'Signed by Customer'
                for(Contract__c contr: newList){
                   
                if(contr.Status__c == 'Signed by Customer' ) 
                
                accIds.add(contr.Account__c);
          
                
        
            // To get the Maximum contract end date of the ""Signed by Customer" Contract

          AggregateResult[] groupedResults =  [SELECT Id,Account__c, MAX(Contract_End_Date__c)
  FROM Contract__c where Account__c IN :accIds and Status__c = 'Signed by Customer' group by Account__c,Id Order by MAX(Contract_End_Date__c) DESC NULLS LAST LIMIT 1];         
            
                     for(AggregateResult ar : groupedResults){
      accMaptomaxcontractexpdate.put((Id)ar.get('Account__c'),(Date)ar.get('expr0'));
      
        System.debug('Accmap for Maximum Contract End date: : '+accMaptomaxcontractexpdate);
        
      d=(Date)ar.get('expr0');
      
      System.debug('Highest Expiry Date: '+d);
      
  }
  
  // To get the Account information associated to the Maximum contract end date of the ""Signed by Customer" Contract
  
   Map<id,Account> accMaptoExpirydate = new Map<id,Account>();
   
          accMaptoExpirydate = new Map<Id, Account>([SELECT Id, Contract_Start_Date__c, Contract_End_Date__c, Contract_Commencement_Date__c, 
                   Contract_Expiry_Date__c, No_of_Contracts__c,Qantas_Annual_Expenditure__c,Contract_Term_in_Months__c,Domestic_Annual_Share__c, International_Annual_Share__c,
                   Unit_Spend_per_term__c, Contracted__c, Account_Contract_No__c,(SELECT Id, Contract_Start_Date__c, Contracted__c, Contract_End_Date__c, 
                   Domestic_Annual_Share__c, International_Annual_Share__c, Type__c,Qantas_Annual_Expenditure__c,Contract_Term_in_Months__c,
                   Unit_Spend_per_term__c,Contract_Number__c FROM Contracts__r where (Contract_End_Date__c = :d and Status__c = 'Signed by Customer')ORDER BY CreatedDate DESC NULLS LAST limit 1) FROM Account where Id IN : accIds ]);
  
  
  // To get the Contract associated to the Account from the map mentioned above

  
   Account accoun = accMaptoExpirydate.get(contr.Account__c);
   
   String Accconno;
   
     for(Contract__c contr2 : accoun.Contracts__r){
         Accconno = contr2.Contract_Number__c;
  expiryDate = contr2.Contract_End_Date__c;
  }
  
    //Setting the Maximum Contract end date to the Account Contract commencement date
   
   accoun.Contract_Expiry_Date__c = expiryDate;
   accoun.Account_Contract_No__c = Accconno;
 
System.debug('Account Contract Expiry Date:'+ accoun.Contract_Expiry_Date__c);
System.debug('Account Contract No: '+  accoun.Account_Contract_No__c);
 updateAccexpdate.add(accoun);
      
        }
        

       
            try{
          
            Database.SaveResult[] srlist = Database.Update(updateAccexpdate, false);
                for (Database.SaveResult sr : srlist){
if (!sr.isSuccess()) {
    
    // Updation failed due to duplicate detected
    for(Database.Error duplicateError : sr.getErrors()){
        Datacloud.DuplicateResult duplicateResult = 
                  ((Database.DuplicateError)duplicateError).getDuplicateResult();
        System.debug('Duplicate records have been detected by ' + 
                  duplicateResult.getDuplicateRule());
        System.debug(duplicateResult.getErrorMessage());
    }

 
    Database.DMLOptions dml = new Database.DMLOptions(); 
    dml.DuplicateRuleHeader.AllowSave = true;
    Database.SaveResult[] sr2list = Database.Update(updateAccexpdate, dml);
     for (Database.SaveResult sr2 : sr2list){
    if (sr2.isSuccess()) {
        System.debug('Duplicate account has been updated in Salesforce!');
    }
}
}
}
            }

catch(Exception e){
               System.debug(' Exception Occured: '+e.getMessage());
               }
        }
        
    }

Kindly help me pls

Thanks in advance
Best Answer chosen by sfdc dev 2264
Charisse de BelenCharisse de Belen
You might be able to just copy your methods exactly as they are from your old class to your new batch class. I do not think you are using the second parameter (oldMap) in each method, so I removed it. This actually makes it easier to convert to the batch class. 

Batch class with only ContractfieldsupdateonAccount method:
public class BatchTriggerHandler implements Database.Batchable<sObject> {
    
    Set<Id> contractIdSet = new Set<Id>();

    // Constructor will take set of new Contract IDs
    public BatchTriggerHandler(Set<Id> contractIdSet){
        this.contractIdSet = contractIdSet;
    }
    
    public Database.QueryLocator start(Database.BatchableContext bc) {
        // Query all Contract records that were in Trigger.new
        return Database.QueryLocator([SELECT Status__c, Account__c FROM Contract__c WHERE Id IN :contractIdSet]);
    }

    // The execute method will call your three methods
    public void execute(Database.BatchableContext bc, List<Contract__c> scope) {
        ContractfieldsupdateonAccount(scope);
    }

    public void finish(Database.BatchableContext bc) { }

    // This is an exact copy of your first method
    // I did not change anything here except remove the second parameter because it was not being used
    public static void ContractfieldsupdateonAccount(List<Contract__c> newList) {
        // Your code will stay exactly the same
    }
    
}

Contract trigger (I only included relevant code, so you will need to add the rest of your code):
trigger ContractTrigger on Contract__c (after update, after insert) {

	Set<Id> contractIdSet = new Set<Id>();

	try {
		if (Trigger.isUpdate) {
			for (Contract__c contract : Trigger.new) {
				contractIdSet.add(contract.Id);
			}

			BatchTriggerHandler bth = new BatchTriggerHandler(contractIdSet);
			Database.executeBatch(bth);
		}
	} catch(Exception e) {
		// ...
	}

}

I did not look very closely at your logic in the three methods, so you need to check that all things are working correctly.

Remember that there are limits to how many queries and DML transactions you can perform in each batch (https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_gov_limits.htm).

All Answers

Charisse de BelenCharisse de Belen
Hello,

If you are going to call a batch class from a trigger, you have to be very careful not to go over the limit of running 5 batch jobs at a time.

Here is the documentation for implementing the Database.Batchable interface, so you can look through and get an idea for how to convert your code to a batch class: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_batch_interface.htm

Here are some important points:
  • Use the start method to collect all the records you want to process. These records will be divided into batches and passed into the execute method.
  • Use the execute method to process each batch of records.
  • Use the finish method to execute any logic that you want to perform after all the records have been processed.
Based on your existing code, it looks like you will want to put your three trigger handler methods in the batch class and call the three of them in the batch execute method. You will then call the batch class from your trigger using the Database.executeBatch method.

Here is an article that gives a good template for executing Batch Apex from a trigger: http://sfdcsrini.blogspot.com/2014/06/how-to-execute-batch-apex-using-apex.html

Here is another article listing Batch Apex best practices: http://sfdcrocket.blogspot.com/2013/12/batch-apex-best-practices.html

I hope this helps!
sfdc dev 2264sfdc dev 2264
Could you please help me with the batch class code for my apex class , Kindly help me pls 
sfdc dev 2264sfdc dev 2264
Please help me with one method so that i can use it for the rest 
Charisse de BelenCharisse de Belen
You might be able to just copy your methods exactly as they are from your old class to your new batch class. I do not think you are using the second parameter (oldMap) in each method, so I removed it. This actually makes it easier to convert to the batch class. 

Batch class with only ContractfieldsupdateonAccount method:
public class BatchTriggerHandler implements Database.Batchable<sObject> {
    
    Set<Id> contractIdSet = new Set<Id>();

    // Constructor will take set of new Contract IDs
    public BatchTriggerHandler(Set<Id> contractIdSet){
        this.contractIdSet = contractIdSet;
    }
    
    public Database.QueryLocator start(Database.BatchableContext bc) {
        // Query all Contract records that were in Trigger.new
        return Database.QueryLocator([SELECT Status__c, Account__c FROM Contract__c WHERE Id IN :contractIdSet]);
    }

    // The execute method will call your three methods
    public void execute(Database.BatchableContext bc, List<Contract__c> scope) {
        ContractfieldsupdateonAccount(scope);
    }

    public void finish(Database.BatchableContext bc) { }

    // This is an exact copy of your first method
    // I did not change anything here except remove the second parameter because it was not being used
    public static void ContractfieldsupdateonAccount(List<Contract__c> newList) {
        // Your code will stay exactly the same
    }
    
}

Contract trigger (I only included relevant code, so you will need to add the rest of your code):
trigger ContractTrigger on Contract__c (after update, after insert) {

	Set<Id> contractIdSet = new Set<Id>();

	try {
		if (Trigger.isUpdate) {
			for (Contract__c contract : Trigger.new) {
				contractIdSet.add(contract.Id);
			}

			BatchTriggerHandler bth = new BatchTriggerHandler(contractIdSet);
			Database.executeBatch(bth);
		}
	} catch(Exception e) {
		// ...
	}

}

I did not look very closely at your logic in the three methods, so you need to check that all things are working correctly.

Remember that there are limits to how many queries and DML transactions you can perform in each batch (https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_gov_limits.htm).
This was selected as the best answer
sfdc dev 2264sfdc dev 2264
Thanks a lot one small clarification

what does the lineno 24 indicate

that method logic has to come under execute method right ?


    public void execute(Database.BatchableContext bc, List<Contract__c> scope) {


    public void execute(Database.BatchableContext bc, List<Contract__c> scope) {

//complete code for this method has to be put here right
}
}
 
rajat Maheshwari 6rajat Maheshwari 6

Hi sfdc,

Yes, u r right according to "Charisse" logic, Line no.24 indicate that the void function are called under execute method to make code more readable.

Thanks
Rajat Maheshwari
rajatzmaheshwari@gmail.com

sfdc dev 2264sfdc dev 2264
so it under the execute method i have to write my code like this right ?
 
public void execute(database,batchablecontext bc){


// callig all my 3 methods inside execute method


 public static void ContractfieldsupdateonAccount(List<Contract__c> newList, Map<Id, Contract__c> oldMap){
         
            Map<Id, Date> accMaptomaxcontractenddate = new Map<Id, Date>();
            Set<Id> accIds = new Set<Id>();
            List<Account> updateAcccontinfo = new List<Account>();
            Date d;
                
                        //Collecting the Account information from the Contract where the Status is 'Signed by Customer'
                        
                        for(Contract__c contr: newList){
        
                  if(contr.Status__c == 'Signed by Customer') 
                
                accIds.add(contr.Account__c);
                
                  System.debug('Account Ids: '+accIds);

                AggregateResult[] groupedResults = [SELECT Id,Account__c,MAX(Contract_End_Date__c)  
  FROM Contract__c where Account__c IN :accIds and Contracted__c = TRUE group by Account__c,Id ORDER BY MAX(Contract_End_Date__c) DESC NULLS LAST LIMIT 1]; 
                     // To get the Maximum contract end date of the Active (End Date > Today > Start date) Contract
            
                     for(AggregateResult ar :groupedResults){
  
  d = (Date)ar.get('expr0');
 System.debug('Maximum Contract End date: '+d);
  accMaptomaxcontractenddate.put((Id)ar.get('Account__c'),(Date)ar.get('expr0'));
  System.debug('Accmap for contracted Maximum Contract End date: : '+accMaptomaxcontractenddate);
  }
                   // To get the Account information associated to the Maximum contract end date of the Active (End Date > Today > Start date) Contract 
                   Map<id,Account> accMaptocontractfields = new Map<id,Account>();
            
                    
                   accMaptocontractfields = new Map<Id, Account>([SELECT Id, Contract_Start_Date__c, Contract_End_Date__c, Contract_Commencement_Date__c, 
                   Contract_Expiry_Date__c, No_of_Contracts__c,Qantas_Annual_Expenditure__c,Contract_Term_in_Months__c,Domestic_Annual_Share__c, International_Annual_Share__c,
                   Unit_Spend_per_term__c, Contracted__c,(SELECT Id, Contract_Start_Date__c, Contracted__c, Contract_End_Date__c, 
                   Domestic_Annual_Share__c, International_Annual_Share__c, Type__c,Qantas_Annual_Expenditure__c,Contract_Term_in_Months__c,
                   Unit_Spend_per_term__c  FROM Contracts__r where (Contract_End_Date__c = :d AND Contracted__c = TRUE) ORDER BY CreatedDate DESC NULLS LAST limit 1 ) FROM Account where Id IN : accIds ]);
                   
                  System.debug('Account map for contract end date:'+accMaptocontractfields);
                    
                     // To get the Contract associated to the Account from the map mentioned above
                  
                  Account acco = accMaptocontractfields.get(contr.Account__c);
                    
                             Date startDate,endDate;
                             Decimal domShare, intShare, unitspend,qantasannual,term;
                             String type;
                             Boolean contracted = false;
                    
                      for(Contract__c contr1 : acco.Contracts__r){
                          
                                  
                                   if(startDate == null && endDate == null){
                                        
                                        startDate = contr1.Contract_Start_Date__c;
                                        endDate = contr1.Contract_End_Date__c;
                                        domShare = contr1.Domestic_Annual_Share__c;
                                        intShare = contr1.International_Annual_Share__c;
                                        unitspend = contr1.Unit_Spend_per_term__c;
                                        qantasannual = contr1.Qantas_Annual_Expenditure__c;
                                        type = contr1.Type__c;
                                        term = contr1.Contract_Term_in_Months__c;
                                        contracted = contr1.Contracted__c;
                                        
                                    }else if(startDate.daysBetween(endDate) < contr1.Contract_Start_Date__c.daysBetween(contr1.Contract_End_Date__c)){
                                        
                                        startDate = contr1.Contract_Start_Date__c;
                                        endDate = contr1.Contract_End_Date__c;
                                        domShare = contr1.Domestic_Annual_Share__c;
                                        intShare = contr1.International_Annual_Share__c;
                                        unitspend = contr1.Unit_Spend_per_term__c;
                                        qantasannual = contr1.Qantas_Annual_Expenditure__c;
                                        type = contr1.Type__c;
                                        term = contr1.Contract_Term_in_Months__c;
                                        contracted = contr1.Contracted__c;
                                    }                                
                                 
                             }
                             
                    //Setting the Highest end date Active Contract information on Account 
                 
                    acco.Contract_Start_Date__c = startDate;
                    acco.Contract_End_Date__c = endDate;
                    acco.Domestic_Annual_Share__c =  domShare;
                    acco.International_Annual_Share__c = intShare;
                    acco.Type__c = type  ;
                    acco.Qantas_Annual_Expenditure__c = qantasannual;
                    acco.Contract_Term_in_Months__c =  term;
                    acco.Unit_Spend_per_term__c = unitspend;
                    acco.Contracted__c =    contracted;
                    
                    
                    System.debug('Account Contract Start Date: '+  acco.Contract_Start_Date__c );
                    System.debug('Account Contract End date: '+acco.Contract_End_Date__c);
                    System.debug('Contract Term in Months: '+acco.Contract_Term_in_Months__c);
                    System.debug('Units spend per term: '+acco.Unit_Spend_per_term__c);
                    System.debug('Account Contract Category: '+acco.Type__c);
                    System.debug('Forecast QF Spend: '  +acco.Qantas_Annual_Expenditure__c);
                    System.debug('Forecast QF Share (Dom) [System]: '+acco.Domestic_Annual_Share__c);
                    System.debug('Forecast QF Share (Int) [System]: '+acco.International_Annual_Share__c);
                    System.debug('Contracted:'+acco.Contracted__c);
                    
                      updateAcccontinfo.add(acco);
                    }

         
                    
            try{
          
            Database.SaveResult[] srlist = Database.Update(updateAcccontinfo, false);
                for (Database.SaveResult sr : srlist){
if (!sr.isSuccess()) {
    
    // Updation failed due to duplicate detected
    for(Database.Error duplicateError : sr.getErrors()){
        Datacloud.DuplicateResult duplicateResult = 
                  ((Database.DuplicateError)duplicateError).getDuplicateResult();
        System.debug('Duplicate records have been detected by ' + 
                  duplicateResult.getDuplicateRule());
        System.debug(duplicateResult.getErrorMessage());
    }

    // If the duplicate rule is an alert rule, we can try to bypass it
    Database.DMLOptions dml = new Database.DMLOptions(); 
    dml.DuplicateRuleHeader.AllowSave = true;
    Database.SaveResult[] sr2list = Database.Update(updateAcccontinfo, dml);
     for (Database.SaveResult sr2 : sr2list){
    if (sr2.isSuccess()) {
        System.debug('Duplicate account has been updated in Salesforce!');
    }
}
}
}
            }

catch(Exception e){
               System.debug(' Exception Occured: '+e.getMessage());
               }
        }
        
        /* This method is being used to populate the Account fields "Contract Commencement Date" of the 
      Minimum contract start date with the status "Signed by Customer" */
        
        public static void contractcommencementdate(List<Contract__c> newList, Map<Id, Contract__c> oldMap){
           
            Map<Id, Date> accMaptomincontractstartdate = new Map<Id, Date>();
            Set<Id> accoIds = new Set<Id>();
            List<Account> updateAcccommdate = new List<Account>();
            Date d;
            Date commencementDate;
            
            //Collecting the Account information from the Contract where the Status is 'Signed by Customer'
        
         for(Contract__c contr: newList){
           
         if(contr.Status__c == 'Signed by Customer' ) 
                
            accoIds.add(contr.Account__c);
    
             // To get the Minimum contract start date of the ""Signed by Customer" Contract    
             
            AggregateResult[] groupedResults = [SELECT Id,Account__c, MIN(Contract_Start_Date__c)  
  FROM Contract__c where Account__c IN :accoIds and Status__c = 'Signed by Customer' group by Account__c,Id ORDER BY MIN(Contract_Start_Date__c) ASC NULLS LAST LIMIT 1];
          
  for(AggregateResult ar : groupedResults){
      accMaptomincontractstartdate.put((Id)ar.get('Account__c'),(Date)ar.get('expr0'));
      
      System.debug('Accmap for Minimum Contract Start date: : '+accMaptomincontractstartdate);
      d=(Date)ar.get('expr0');
      System.debug('Least Commencement Date: '+d);
     }
                 
                 // To get the Account information associated to the Minimum contract start date of the "Signed by Customer" Contract
                 Map<id,Account> accMaptocommencementdate = new Map<id,Account>();
     
                     accMaptocommencementdate = new Map<Id, Account>([SELECT Id, Contract_Start_Date__c, Contract_End_Date__c, Contract_Commencement_Date__c, 
                   Contract_Expiry_Date__c, No_of_Contracts__c,Qantas_Annual_Expenditure__c,Contract_Term_in_Months__c,Domestic_Annual_Share__c, International_Annual_Share__c,
                   Unit_Spend_per_term__c, Contracted__c,(SELECT Id, Contract_Start_Date__c, Contracted__c, Contract_End_Date__c, 
                   Domestic_Annual_Share__c, International_Annual_Share__c, Type__c,Qantas_Annual_Expenditure__c,Contract_Term_in_Months__c,
                   Unit_Spend_per_term__c  FROM Contracts__r where (Contract_Start_Date__c = :d and Status__c = 'Signed by Customer')limit 1 ) FROM Account where Id IN : accoIds]);
  
   
               // To get the Contract associated to the Account from the map mentioned above
   Account accou = accMaptocommencementdate.get(contr.Account__c);
  
  for(Contract__c contr2 : accou.Contracts__r){
  commencementDate = contr2.Contract_Start_Date__c;
  }
  
  //Setting the Minimum Contract start date to the Account Contract commencement date
 
 accou.Contract_Commencement_Date__c =  commencementDate;
 
 System.debug('Account Contract Commenecement Date:'+accou.Contract_Commencement_Date__c);
     updateAcccommdate.add(accou);
      }
           
 
     
        
            try{
          
            Database.SaveResult[] srlist = Database.Update(updateAcccommdate, false);
                for (Database.SaveResult sr : srlist){
if (!sr.isSuccess()) {
    
    // Updation failed due to duplicate detected
    for(Database.Error duplicateError : sr.getErrors()){
        Datacloud.DuplicateResult duplicateResult = 
                  ((Database.DuplicateError)duplicateError).getDuplicateResult();
        System.debug('Duplicate records have been detected by ' + 
                  duplicateResult.getDuplicateRule());
        System.debug(duplicateResult.getErrorMessage());
    }

    // If the duplicate rule is an alert rule, we can try to bypass it
    Database.DMLOptions dml = new Database.DMLOptions(); 
    dml.DuplicateRuleHeader.AllowSave = true;
    Database.SaveResult[] sr2list = Database.Update(updateAcccommdate, dml);
     for (Database.SaveResult sr2 : sr2list){
    if (sr2.isSuccess()) {
        System.debug('Duplicate account has been updated in Salesforce!');
    }
}
}
}
            }

catch(Exception e){
               System.debug(' Exception Occured: '+e.getMessage());
               }
        }
        
        
         public static void contractexpirydate(List<Contract__c> newList, Map<Id, Contract__c> oldMap){
         
          Map<Id, Date> accMaptomaxcontractexpdate = new Map<Id, Date>();
          Set<Id> accIds = new Set<Id>();
          List<Account> updateAccexpdate = new List<Account>();
          Date d;
          Date expiryDate;
        
                //Collecting the Account information from the Contract where the Status is 'Signed by Customer'
                for(Contract__c contr: newList){
                   
                if(contr.Status__c == 'Signed by Customer' ) 
                
                accIds.add(contr.Account__c);
          
                
        
            // To get the Maximum contract end date of the ""Signed by Customer" Contract

          AggregateResult[] groupedResults =  [SELECT Id,Account__c, MAX(Contract_End_Date__c)
  FROM Contract__c where Account__c IN :accIds and Status__c = 'Signed by Customer' group by Account__c,Id Order by MAX(Contract_End_Date__c) DESC NULLS LAST LIMIT 1];         
            
                     for(AggregateResult ar : groupedResults){
      accMaptomaxcontractexpdate.put((Id)ar.get('Account__c'),(Date)ar.get('expr0'));
      
        System.debug('Accmap for Maximum Contract End date: : '+accMaptomaxcontractexpdate);
        
      d=(Date)ar.get('expr0');
      
      System.debug('Highest Expiry Date: '+d);
      
  }
  
  // To get the Account information associated to the Maximum contract end date of the ""Signed by Customer" Contract
  
   Map<id,Account> accMaptoExpirydate = new Map<id,Account>();
   
          accMaptoExpirydate = new Map<Id, Account>([SELECT Id, Contract_Start_Date__c, Contract_End_Date__c, Contract_Commencement_Date__c, 
                   Contract_Expiry_Date__c, No_of_Contracts__c,Qantas_Annual_Expenditure__c,Contract_Term_in_Months__c,Domestic_Annual_Share__c, International_Annual_Share__c,
                   Unit_Spend_per_term__c, Contracted__c, Account_Contract_No__c,(SELECT Id, Contract_Start_Date__c, Contracted__c, Contract_End_Date__c, 
                   Domestic_Annual_Share__c, International_Annual_Share__c, Type__c,Qantas_Annual_Expenditure__c,Contract_Term_in_Months__c,
                   Unit_Spend_per_term__c,Contract_Number__c FROM Contracts__r where (Contract_End_Date__c = :d and Status__c = 'Signed by Customer')ORDER BY CreatedDate DESC NULLS LAST limit 1) FROM Account where Id IN : accIds ]);
  
  
  // To get the Contract associated to the Account from the map mentioned above

  
   Account accoun = accMaptoExpirydate.get(contr.Account__c);
   
   String Accconno;
   
     for(Contract__c contr2 : accoun.Contracts__r){
         Accconno = contr2.Contract_Number__c;
  expiryDate = contr2.Contract_End_Date__c;
  }
  
    //Setting the Maximum Contract end date to the Account Contract commencement date
   
   accoun.Contract_Expiry_Date__c = expiryDate;
   accoun.Account_Contract_No__c = Accconno;
 
System.debug('Account Contract Expiry Date:'+ accoun.Contract_Expiry_Date__c);
System.debug('Account Contract No: '+  accoun.Account_Contract_No__c);
 updateAccexpdate.add(accoun);
      
        }
        

       
            try{
          
            Database.SaveResult[] srlist = Database.Update(updateAccexpdate, false);
                for (Database.SaveResult sr : srlist){
if (!sr.isSuccess()) {
    
    // Updation failed due to duplicate detected
    for(Database.Error duplicateError : sr.getErrors()){
        Datacloud.DuplicateResult duplicateResult = 
                  ((Database.DuplicateError)duplicateError).getDuplicateResult();
        System.debug('Duplicate records have been detected by ' + 
                  duplicateResult.getDuplicateRule());
        System.debug(duplicateResult.getErrorMessage());
    }

 
    Database.DMLOptions dml = new Database.DMLOptions(); 
    dml.DuplicateRuleHeader.AllowSave = true;
    Database.SaveResult[] sr2list = Database.Update(updateAccexpdate, dml);
     for (Database.SaveResult sr2 : sr2list){
    if (sr2.isSuccess()) {
        System.debug('Duplicate account has been updated in Salesforce!');
    }
}
}
}
            }

catch(Exception e){
               System.debug(' Exception Occured: '+e.getMessage());
               }
        }
        
    }

Is my above logic inside my execute method right ?
sfdc dev 2264sfdc dev 2264
I am calling all my 3 methods inside my execute method like this

public void execute(){

public method 1{
// logic in method 1 from main class

}

public method 2{
//logic in method 2 from main class
}

public method 3{
//logic in method 3 from main class
}
}

and that one query can alone be there in start method right , Please confirm


 
Charisse de BelenCharisse de Belen
You will put the logic for your three methods outside of the execute method, but you will call them inside of the execute method, like this:
 
public void execute() {
  // call method 1
  // call method 2
  // call method 3
}

public method 1 {
  // logic in method 1
}

public method 2 {
  // logic in method 2
}

public method 3 {
  // logic in method 3
}
Yes, you will use only the one query in the the start method.
 
sfdc dev 2264sfdc dev 2264
thanks so much bro for the much needed help , 


just one small confirmation at end

In the trigger i just have to call my batch class thats it right , i mean the above trigger mentioned by you is all it requires right , or should i call the batchclass.method name there also ?

 
trigger ContractTrigger on Contract__c (after update, after insert) {

	Set<Id> contractIdSet = new Set<Id>();

	try {
		if (Trigger.isUpdate) {
			for (Contract__c contract : Trigger.new) {
				contractIdSet.add(contract.Id);
			}

			BatchTriggerHandler bth = new BatchTriggerHandler(contractIdSet);
			Database.executeBatch(bth);
		}
	} catch(Exception e) {
		// ...
	}

}


 
My original trigger :

MY TRIGGER CODE:

trigger ContractTrigger on Contract__c(After Update,After Insert) {    
    try{
        Trigger_Status__c ts = Trigger_Status__c.getValues('ContractTrigger');
        if(ts.Active__c){
            
            if(Trigger.isUpdate){

                TravelFundHandler.ValidateContractTermination(Trigger.New,Trigger.oldMap);
                ContractTriggerHandler.ContractfieldsupdateonAccount(Trigger.New, Trigger.oldMap);
                ContractTriggerHandler.contractcommencementdate(Trigger.New, Trigger.oldMap);
                ContractTriggerHandler.contractexpirydate(Trigger.New, Trigger.oldMap);
                 
            }  
            if(Trigger.isInsert){

                
                TravelFundHandler.travelFundMethod(Trigger.New,Trigger.oldMap);
              
            } 
            if(Trigger.isUpdate && TravelFundHandler.firstRun){
                TravelFundHandler.firstRun=false;
                TravelFundHandler.SignOnMethod(Trigger.New,Trigger.oldMap);
                
            }
          
           
            
        }
        
    }catch(Exception e){
        System.debug('Error Occured From Contract Trigger: '+e.getMessage());
    }
}

 
sfdc dev 2264sfdc dev 2264
i triged the above code , but getting the following error

Error: Compile Error: Method does not exist or incorrect signature: Database.QueryLocator(List<Contract__c>) at line 10 column 16


global Database.QueryLocator start(Database.BatchableContext bc) {
        // Query all Contract records that were in Trigger.new
        return Database.QueryLocator([SELECT Status__c, Account__c FROM Contract__c WHERE Id IN :contractIdSet]);
    }
Charisse de BelenCharisse de Belen
Sorry, that line should be like this:
return Database.getQueryLocator( ... );

To answer your question from before, you do not need to call the batchclass.methodname. If you have more questions about how the batch class works, I recommend checking the Batch Apex documentation (https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_batch_interface.htm).