0

I am unable get how I can access the dynamic fields from dynamic objects in the execute method. Here start method is returning multiple records with different fields from different object. I want to insert new records for those with the same field values from the extracted records. here is my start method:

    public Database.QueryLocator start(Database.BatchableContext bc) {
    String query = '';
    Map<String,Record_Condition_Metadata__mdt> mapTargets = new Map<String,Record_Condition_Metadata__mdt>([ select Fields__c,Object_Name__c,Condition__c from Record_Condition_Metadata__mdt]);
    Map<String,String> dynamicCondition = new Map<String,String>();
    Map<String,String> selectedFields = new Map<String,String>();        

    for(Record_Condition_Metadata__mdt target : mapTargets.values())
    {
        String objectList = target.Object_Name__c;
        dynamicCondition.put(objectList, target.Condition__c);
        String condition = dynamicCondition.get(objectList);
        selectedFields.put(objectList, target.Fields__c);
        String selectedField = selectedFields.get(objectList);

        query = 'SELECT '+ selectedField +' FROM ' + objectList + ' WHERE ' + condition;
        System.debug('query is '+ query );

    }
    return Database.getQueryLocator(query);


} 
public void execute(Database.BatchableContext bc, List<sObject> sc){

} 

2 Answers 2

3

First, you need to change how you populate the query string. In the current design, the query string will get overwritten again and again and only the last look iteration will determine what it looks like. You need to create the query outside the loop, then only iterate to populate the required fields.

Second, it seems like you're trying to query from multiple objects. In SOQL, as oppose to SQL, you can only query from a single object per each query. You can work on a collection of multiple objects in a batch, but your start method will need to return an Iterable rather than a QueryLocator. This means you'll have to build your records list and insert them into a List, then return that list.

Next, when implementing the execute method you'll need to use the syntax of [record].get('[fieldname]') to dynamically access fields, while keeping in mind you need to perform casting on the result if you intend to do something with that field beyond retrieving it.

Lastly, I recommend using the SObjectField object to accumulate and query on fields, rather than strings. That's what represents a field in Apex, not strings.

More info here: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_class_Schema_SObjectField.htm

0
1

@Eran did answered everything of your question. For starting you can try someting like this:

public Iterable<sObject> start(Database.BatchableContext bc) {
   List<sObject> toReturn = new List<sObject>();

   //Fill your list here with all your records you want to handle
   //.....

   return toReturn;
} 

Note, that when returning an Iterable, the SOQL governor limit is still enforced: Using Batch Apex

If you use an iterable, the governor limit for the total number of records retrieved by SOQL queries is still enforced

Your execute function could look something like this:

public void execute(Database.BatchableContext bc, List<sObject> sc){
   for(sObject s : sc)
   {
       //Parse the sobject to specific type if necessary
       //....
       //Get the field values of the current record by using the get-function
   }

} 

The look of your execute function depends of what you want to do there. If you want to access a list of field depending on the type of the current sObject you could safe them in a Map and fill it inside the start-function.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .