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
Shree KShree K 

what is the difference between Database.stateful and Database.saveResult?

Hi All,
after a bit of reading about to have the total count of the records which were processed in the Batch class, I came across both Database.Stateful and Database.Saveresult online, but both seems to be doing pretty much samething one itself and by combining both.

1) If we have to have the total count the records which were processed  in the batch apex, should we use both Database.stateful and Database.saveResult, if not ,can someone please explain me the difference between these two and their explicit usage ? 

2) In the 1st link below some of them suggesting database.stateful alone and some database.saveresult alone but in the 2nd link both were used to get the count of the records which were processd, actually this caused me the confusion.
https://salesforce.stackexchange.com/questions/82969/count-of-records-processed-during-batch
https://developer.salesforce.com/forums/?id=906F0000000kGqFIAU
3) once the batch is complete, where would i be able to see the results?
help will be appreciated,

Thanks,
Shree
Best Answer chosen by Shree K
Raj VakatiRaj Vakati
Database.Statefu

If you specify Database.Stateful in the class definition, you can maintain state across these transactions. When using Database.Stateful, only instance member variables retain their values between transactions. Static member variables don’t retain their values and are reset between transactions. Maintaining state is useful for counting or summarizing records as they’re processed. For example, suppose your job processed opportunity records. You could define a method in execute to aggregate totals of the opportunity amounts as they were processed.

Lets take an example here 
 
global class SummarizeAccountTotal implements 
    Database.Batchable<sObject>, Database.Stateful{

   global final String Query;
   global integer Summary;
  
   global SummarizeAccountTotal(String q){Query=q;
     Summary = 0;
   }

   global Database.QueryLocator start(Database.BatchableContext BC){
      return Database.getQueryLocator(query);
   }
   
   global void execute(
                Database.BatchableContext BC, 
                List<sObject> scope){
      for(sObject s : scope){
         Summary = Integer.valueOf(s.get('total__c'))+Summary;
      }
   }

global void finish(Database.BatchableContext BC){
   }
}


In the above example Consider the first case . 

Case 1  : Without Stateful 

With out database.stateful the 
Summary value will be reset to zero for every batch 

Case 2 : With Stateful 

With database.stateful the 
Summary value will not reset for every batch execute method 



database.saveresult 

Datebase.saveResult is an result of an insert or update DML operation returned by a Database method whihc contains both the success and error deetails 
 
// Create two accounts, one of which is missing a required field
Account[] accts = new List<Account>{
    new Account(Name='Account1'),
    new Account()};
Database.SaveResult[] srList = Database.insert(accts, false);

// Iterate through each returned result
for (Database.SaveResult sr : srList) {
    if (sr.isSuccess()) {
        // Operation was successful, so get the ID of the record that was processed
        System.debug('Successfully inserted account. Account ID: ' + sr.getId());
    }
    else {
        // Operation failed, so get all errors                
        for(Database.Error err : sr.getErrors()) {
            System.debug('The following error has occurred.');                    
            System.debug(err.getStatusCode() + ': ' + err.getMessage());
            System.debug('Account fields that affected this error: ' + err.getFields());
        }
    }
}

In the above example shows how to obtain and iterate through the returned Database.SaveResult objects. It inserts two accounts using Database.insert with a false second parameter to allow partial processing of records on failure. One of the accounts is missing the Name required field, which causes a failure. Next, it iterates through the results to determine whether the operation was successful or not for each record. It writes the ID of every record that was processed successfully to the debug log, or error messages and fields of the failed records. This example generates one successful operation and one failure.​​​​​​​
 

All Answers

Raj VakatiRaj Vakati
Database.Statefu

If you specify Database.Stateful in the class definition, you can maintain state across these transactions. When using Database.Stateful, only instance member variables retain their values between transactions. Static member variables don’t retain their values and are reset between transactions. Maintaining state is useful for counting or summarizing records as they’re processed. For example, suppose your job processed opportunity records. You could define a method in execute to aggregate totals of the opportunity amounts as they were processed.

Lets take an example here 
 
global class SummarizeAccountTotal implements 
    Database.Batchable<sObject>, Database.Stateful{

   global final String Query;
   global integer Summary;
  
   global SummarizeAccountTotal(String q){Query=q;
     Summary = 0;
   }

   global Database.QueryLocator start(Database.BatchableContext BC){
      return Database.getQueryLocator(query);
   }
   
   global void execute(
                Database.BatchableContext BC, 
                List<sObject> scope){
      for(sObject s : scope){
         Summary = Integer.valueOf(s.get('total__c'))+Summary;
      }
   }

global void finish(Database.BatchableContext BC){
   }
}


In the above example Consider the first case . 

Case 1  : Without Stateful 

With out database.stateful the 
Summary value will be reset to zero for every batch 

Case 2 : With Stateful 

With database.stateful the 
Summary value will not reset for every batch execute method 



database.saveresult 

Datebase.saveResult is an result of an insert or update DML operation returned by a Database method whihc contains both the success and error deetails 
 
// Create two accounts, one of which is missing a required field
Account[] accts = new List<Account>{
    new Account(Name='Account1'),
    new Account()};
Database.SaveResult[] srList = Database.insert(accts, false);

// Iterate through each returned result
for (Database.SaveResult sr : srList) {
    if (sr.isSuccess()) {
        // Operation was successful, so get the ID of the record that was processed
        System.debug('Successfully inserted account. Account ID: ' + sr.getId());
    }
    else {
        // Operation failed, so get all errors                
        for(Database.Error err : sr.getErrors()) {
            System.debug('The following error has occurred.');                    
            System.debug(err.getStatusCode() + ': ' + err.getMessage());
            System.debug('Account fields that affected this error: ' + err.getFields());
        }
    }
}

In the above example shows how to obtain and iterate through the returned Database.SaveResult objects. It inserts two accounts using Database.insert with a false second parameter to allow partial processing of records on failure. One of the accounts is missing the Name required field, which causes a failure. Next, it iterates through the results to determine whether the operation was successful or not for each record. It writes the ID of every record that was processed successfully to the debug log, or error messages and fields of the failed records. This example generates one successful operation and one failure.​​​​​​​
 
This was selected as the best answer
Shree KShree K
Hi Raj,

Thanks for your time, I posted the question here after a lot of reading in different places online, I must say, your answer is the best, I just have missed one piece of information, so, after the batches run by maintaing state, where would i be able to see the total count of the records processed, because i get to see few batch classes where state was maintained by the way you explained but without save result so , just wondering where would the result be? in any kind of logs, or sould i put debug logs and check later ?
Raj VakatiRaj Vakati
Set the debug logs .. Update the code as below 
global class SummarizeAccountTotal implements 
    Database.Batchable<sObject>, Database.Stateful{

   global final String Query;
   global integer Summary;
  
   global SummarizeAccountTotal(String q){Query=q;
     Summary = 0;
   }

   global Database.QueryLocator start(Database.BatchableContext BC){
      return Database.getQueryLocator(query);
   }
   
   global void execute(
                Database.BatchableContext BC, 
                List<sObject> scope){

System.debug('Count '+Summary)

      for(sObject s : scope){
         Summary = Integer.valueOf(s.get('total__c'))+Summary;
      }
   }

global void finish(Database.BatchableContext BC){
   }
}

From Setup, enter Debug Logs in the Quick Find box, then click Debug Logs.
Click New Setup debug  logs .. refer this link 

https://help.salesforce.com/articleView?id=code_add_users_debug_log.htm&type=5