3

Hi I created a batch class, that uses custom setting list to filter the records being queried. Now my issue is, they don't want to touch the query if for example they add another record in the custom setting,

Custom Setting Sample Record

Affliate - AU, Type - Doctor

What if client added a new Record =

Affiliate - MY, Type- Nurse

This is the Query Locator method

 public Map<String, PC_Roche_PhysicianUserBatchSetting__c> physicianUserBatchMap = new Map<String,PC_Roche_PhysicianUserBatchSetting__c>();

global Database.QueryLocator start(Database.BatchableContext BC){
    //gets all custom setting record
    for (PC_Roche_PhysicianUserBatchSetting__c pumapping: (list<PC_Roche_PhysicianUserBatchSetting__c>)fflib_Roche_Application.Selector.newInstance(PC_Roche_PhysicianUserBatchSetting__c.SObjectType).selectSObjects()) {
        //Name => CS Values
        physicianUserBatchMap.put(pumapping.Name, pumapping);
    }

    decimal hoursDecimal = physicianUserBatchMap.get(PC_Roche_Constants.HCP_BATCH_SETTING_AU).PC_Roche_Hours__c;
    integer hoursInteger = hoursDecimal.intValue();

    DateTime dt = System.Now().addHours(-hoursInteger);

    return Database.getQueryLocator([SELECT ID, PC_Roche_UCI_ID__c,Type 
                                    FROM Account
                                    WHERE PC_Roche_UCI_ID__c != null
                                    AND (PC_Roche_Affiliate__c =: physicianUserBatchMap.get(PC_Roche_Constants.HCP_BATCH_SETTING_AU).PC_Roche_Affiliate__c
                                    AND Type IN : physicianUserBatchMap.get(PC_Roche_Constants.HCP_BATCH_SETTING_AU).PC_Roche_Account_Type__c.split('\\;')
                                    AND SystemModStamp >=: dt)
                                    //FOR FUTURE AFFILIATE
                                    ]);
}

How can I make the returned query more dynamic in regards to not updating and not using the PC_Roche_Constants.HCP_BATCH_SETTING_AU.

Thank you for any help.

EDIT... Was able to think of something

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

    for (PC_Roche_PhysicianUserBatchSetting__c pumapping: (list<PC_Roche_PhysicianUserBatchSetting__c>)fflib_Roche_Application.Selector.newInstance(PC_Roche_PhysicianUserBatchSetting__c.SObjectType).selectSObjects()) {
        //Name => CS Values
        physicianUserBatchMap.put(pumapping.PC_Roche_Affiliate__c, pumapping);
    }

    for(Account accRecord : [SELECT ID,
                            Type,
                            PC_Roche_UCI_ID__c,
                            SystemModStamp 
                            FROM Account 
                            WHERE PC_Roche_Affiliate__c IN : physicianUserBatchMap.keyset()
                            AND PC_Roche_UCI_ID__c != null]){

        if(physicianUserBatchMap.get(accRecord.PC_Roche_Affiliate__c).PC_Roche_Account_Type__c.split('\\;').contains(accRecord.Type) &&
        physicianUserBatchMap.get(accRecord.PC_Roche_Affiliate__c).PC_Roche_Hours__c != null){

            decimal hoursDecimal = physicianUserBatchMap.get(accRecord.PC_Roche_Affiliate__c).PC_Roche_Hours__c;
            integer hoursInteger = hoursDecimal.intValue();
            DateTime dt = System.Now().addHours(-hoursInteger);

            if(accRecord.SystemModStamp >= dt){
                accId.add(accRecord.Id);
            }

        }                            
    }

    return Database.getQueryLocator([SELECT ID, PC_Roche_UCI_ID__c FROM ACCOUNT WHERE ID IN: accId]);

Any suggestion for improvement will do.

EDIT - The Issue is it might hit SOQL Limit

3
+100

I suggest you use batch chaining, where in the finish method of the batchable you execute for the next row of the custom setting:

public class MyBatchable implements Database.Batchable<SObject>, Database.Stateful {

    private PC_Roche_PhysicianUserBatchSetting__c[] settings = ...;
    private Integer settingsIndex = 0;
    private Integer batchSize = 50;

    public Database.QueryLocator start(Database.BatchableContext bc) {
        PC_Roche_PhysicianUserBatchSetting__c setting = settings[settingsIndex];
        // Query using the setting
        ...
    }

    ...

    public void finish(Database.BatchableContext bc) {
        if (settingsIndex < settings.size() - 1) {
            // Move on to next chain item
            settingsIndex++;
            Database.executeBatch(this, batchSize);
        } else {
            // Chain is finished - all done
        }
    }
}

Using the Database.Stateful marker interface means the local variables are preserved. If there were a large number of rows, you could re-query those in each start method instead of including them in the state.

Using this approach, a separate simple query is done for each of the custom setting rows and each set of query results can consume as many batches as it needs to complete.

  • Thanks for your answer man, it gave me an idea. – imajmdf Jun 14 '19 at 12:08
0

So you want the system to know that you should use the new MY record and ignore the AU record? You can either have a checkbox on the setting that indicates that it should be used, or you can delete the AU record. Hope that helps.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.