zoukankan      html  css  js  c++  java
  • SFDC 在Batch Apex中使用Aggregate SOQL统计查询语句及结果

    在Batch Apex中使用Aggregate SOQL统计查询语句及结果


    前言

    Database.Batchable in Salesforce, but if you want to use SOQL having aggregate functions like SUM(), MAX(), COUNT() on results grouped by “GROUP BY” clause in start execution, changing to interface Database.Batchable isn’t a workable way, because it fails with the below compile error :

    Class must implement the global interface method: Iterable start(Database.BatchableContext) from Database.Batchable

    The following sample code will explain this.

    /*
     * Compile error : Class must implement the global interface method: Iterable<AggregateResult> start(Database.BatchableContext) from Database.Batchable<AggregateResult>
     */
    global class SampleAggregateBatch implements Database.Batchable<AggregateResult> {
      // The batch job starts
      global Database.Querylocator start(Database.BatchableContext bc){
        String query = 'SELECT COUNT(Id), AccountId FROM Contact GROUP BY AccountId';
        return Database.getQuerylocator(query);
      } 
      // The batch job executes and operates on one batch of records
      global void execute(Database.BatchableContext bc, List<sObject> scope){ }
      // The batch job finishes
      global void finish(Database.BatchableContext bc){ }
    }
    

    To fix this, using Apex classes that implement Iterator<AggregateResult> and Iterable<AggregateResult> seems the only way for now.

    Here is the outline what we should do.

    1. Create an Apex class implements Iterator<AggregateResult>.
    2. Create an Apex class implements Iterable<AggregateResult>.
    3. Implementing to Database.Batchable<AggregateResult>, and Using Iterable at start execution in Batch Apex.

    Let’s get started.

    Iterator Apex class

    Create an Apex class named “AggregateResultIterator” with the following source code :

    global class AggregateResultIterator implements Iterator<AggregateResult> {
      AggregateResult [] results {get;set;}
      // tracks which result item is returned
      Integer index {get; set;} 
           
      global AggregateResultIterator(String query) {
        index = 0;
        results = Database.query(query);            
      } 
    
      global boolean hasNext(){ 
        return results != null && !results.isEmpty() && index < results.size(); 
      }    
    
      global AggregateResult next(){        
        return results[index++];            
      }       
    }   
    

    Iterable Apex class

    Create an Apex class named “AggregateResultIterable” with the following source code :

    global class AggregateResultIterable implements Iterable<AggregateResult> {
      private String query;
    
      global AggregateResultIterable(String soql){
        query = soql;
      }
    
      global Iterator<AggregateResult> Iterator(){
        return new AggregateResultIterator(query);
      }
    }
    

    Batch Apex

    Then implement Batch Apex from Database.Batchable<AggregateResult>, and use Iterable<AggregateResult>, AggregateResultIterable instead of Database.QueryLocator at start execution, as the following source code :

    global class SampleAggregateBatch implements Database.Batchable<AggregateResult> {
      // The batch job starts
      global Iterable<AggregateResult> start(Database.BatchableContext bc){
        String query = 'SELECT COUNT(Id) cnt, AccountId FROM Contact GROUP BY AccountId';
        return new AggregateResultIterable(query);
      } 
      // The batch job executes and operates on one batch of records
      global void execute(Database.BatchableContext bc, List<sObject> scope){ 
        for(sObject sObj : scope) {
          AggregateResult ar = (AggregateResult)sObj;
          System.debug('>>>> COUNT : ' + ar.get('cnt'));
        }
      }
      // The batch job finishes
      global void finish(Database.BatchableContext bc){ }
    }
    

    Operation check

    Run SampleAggregateBatch and check debug log.

    // Run batch apex
    SampleAggregateBatch batch = new SampleAggregateBatch();
    Database.executebatch(batch, 200);
    
    // Debug log output
    11:36:35.0 (14518157)|USER_DEBUG|[11]|DEBUG|>>>> COUNT : 1
    11:36:35.0 (14903974)|USER_DEBUG|[11]|DEBUG|>>>> COUNT : 3
    11:36:35.0 (15035196)|USER_DEBUG|[11]|DEBUG|>>>> COUNT : 1
    

    It seems working fine! : )

    Enjoy it!

    Resource

    转载来源:https://www.xgeek.net/zh/salesforce/using-aggregate-soql-queries-results-in-batch-apex/

  • 相关阅读:
    2020年3月22日
    2021年3月21日
    2021年3月20日
    人件集阅读笔记02
    2021年3月19日
    2021年3月18日
    2021年3月17日
    2021年3月16日
    2021年3月15日
    梦断代码阅读笔记01
  • 原文地址:https://www.cnblogs.com/paynev/p/15129151.html
Copyright © 2011-2022 走看看