Skip to content

Updating Records via Batch Apex Part 2: Field Changes

In the first part of this series I showed how to use a batch class to run just an update on a set of records by just supplying a query.  Now we’ll expand on that to specify a field and change it’s value by adding a few more arguments when we call the batch as well as the logic to handle a change using describe methods.  Describe methods can be used to dynamically setup an Object, Field or other metadata – for this we’ll need to retrieve the Object we want to interact with as well as the Field the change is being applied to, this requires three new arguments when the batch is called.

The first is a String where the Object API Name will be passed to, a second String for the Field API Name and finally an Object with the value to assign to the field.  The Object Data Type will allow us to assign any Primitive Data Type to it so we can apply it to any field.

global util_sObjectFieldUpdaterBatch(String qry, string nextBat, string obj, string field, object changeObj)

We need to handle assigning these to variables and converting the obj and field arguments from strings to an sObjectType and sObjectField respectively.  We’re also going to get a map of the Schema using Schema.getGlobalDescribe() which returns a map of all sObject names (keys) to sObject tokens (values) for the standard and custom objects defined in your organization.

global string query;
global string sObjName;
global string sObjFieldName;
global sObjectType sObjType;
global sObjectField sObjField;
global object changeTo;

private Map<String, Schema.SObjectType> smap = Schema.getGlobalDescribe();

global util_sObjectFieldUpdaterBatch(String qry, string obj, string field, object changeObj)

The logic that’s placed inside of the inner class will assign our arguments to our variables.  First by getting the sObjectType of the Object we’re targeting (obj argument) from the Schema Map we built.  Once we have the sObjectType we use another describe method to get a map of fields within that Object using sObjType.getDescribe().fields.getMap().

global util_sObjectFieldUpdaterBatch(String qry, string nextBat, string obj, string field, object changeObj) {
    Query = qry;

    sObjName = obj;

    changeTo = changeObj;

    SObjectType sObjType;

    if(smap.get(obj) != null){

        sObjType = smap.get(obj);

        Map<String,Schema.SObjectField> fieldMap = sObjType.getDescribe().fields.getMap(); 

        if(fieldMap.get(field) != null){

       	    sObjFieldName = field;

            sObjField = fieldMap.get(field);

        }

    }

}

To finish this off we add a few lines of code to the Execute to loop through our data and assign the new values.

global void execute(Database.BatchableContext bcMain, List<sObject> scope) {

    for(sObject s : scope){
      	s.put(sObjField, changeTo);
    }

    if(scope.size() > 0) {
        update scope;
    }
}

That’s it! Below is the final Product, as always here’s the GitHub link to the Class.

global class util_sObjectFieldUpdaterBatch implements Database.Batchable<sobject>, Database.Stateful {

    /**
    Run This Batch

    string query = ;
    string sObj = ;
    string field = ;
    object changeTo = ;
    integer batSize = ;

    ID idBatch = Database.executeBatch(new util_sObjectFieldUpdaterBatch(query,nextBatch,sObj,field,changeTo), batSize);
    **/

    global string query;

    global string sObjName;
    global string sObjFieldName;
    global sObjectType sObjType;
    global sObjectField sObjField;

    global object changeTo;

    private Map<String, Schema.SObjectType> smap = Schema.getGlobalDescribe();

    global integer NumBatches;

    global util_sObjectFieldUpdaterBatch(String qry, string obj, string field, object changeObj) {

        Query = qry;

        sObjName = obj;

        changeTo = changeObj;

        SObjectType sObjType;

        if(smap.get(obj) != null){

            sObjType = smap.get(obj);

            Map<String,Schema.SObjectField> fieldMap = sObjType.getDescribe().fields.getMap(); 

            if(fieldMap.get(field) != null){

            	sObjFieldName = field;

            	sObjField = fieldMap.get(field);

            }

        }

    }

    global Database.QueryLocator start(Database.BatchableContext bcMain) {
        return Database.getQueryLocator(Query);
    }

    global void execute(Database.BatchableContext bcMain, List<sObject> scope) {

        for(sObject s : scope){
        	s.put(sObjField, changeTo);
        }

        if(scope.size() > 0) {
            update scope;
        }
    }

    global void finish(Database.BatchableContext bcMain) {

    } 

}
Published inApexBatch Apex

Be First to Comment

Leave a Reply