1

I have the following code and would like to perform the DML operation outside the loop. However, I cannot seem to find any way in doing this at the moment:

private void processResult(List<RS_Assessment__c> newlist){
    List<Id> activityList = new List<Id>();
    for (RS_Assessment__c assessment : newlist){
        if (assessment.Activity__c != null && assessment.Activity__r.Actual_Date__c == null){
            if (assessment.Activity__r.Last_Assessment_Date__c == null){
                activityList.add(assessment.Activity__c);
            }
        }
    }
    List<RS_Activity__c> processesToUpdate = [SELECT Id FROM RS_Activity__c WHERE Id IN: activityList];
    if (processesToUpdate.size() > 0){
        for (RS_Activity__c act : processesToUpdate){
            RS_Assessment__c assessment = [SELECT Id, Assessment_Date__c FROM RS_Assessment__c WHERE Activity__c  =: act.Id LIMIT 1]; //need to move soql out
            act.Actual_Date__c = assessment.Assessment_Date__c;
        }
        update processesToUpdate;
    }
}

I need to move the dml in the second for loop outside the loop. Thanks in advance

4

You need to use a map and build it from the results of your Activity query.

The second part of your code should be rewritten as this:

RS_Activity__c[] updateProcesses = new RS_Activity__c[]{};
RS_Activity__c[] allProcesses = [SELECT Id FROM RS_Activity__c WHERE Id IN: activityList];
RS_Assessment__c[] assessments = [SELECT Id, Assessment_Date__c FROM RS_Assessment__c WHERE Activity__c  IN :activityList];

Map<Id,RS_Assessment__c> assessmentsByActivityId = new Map<Id,RS_Assessment__c>();

for (RS_Assessment__c assessment : asessments){
    assessmentsByActivityId.put(asessment.Activity__c,assessment);
}

for (RS_Activity__c act : allProcesses){
    RS_Assessment__c assessment = assessmentsByActivityId.get(act.Id);
    if (assessment == null){
        continue;
    }
    act.Actual_Date__c = assessment.Assessment_Date__c;
    updateProcesses.add(act);
}
update updateProcesses;

So, as you can see:

  • Query into a list. Get all RS_Assessment__c objects.
  • Build the map, indexed by RS_Activity__c id.
  • Loop through RS_Activity__c records, and attempt to retrieve a related RS_Assessment__c.
  • If found, perform change.

UPDATE Have added an 'all' list and an 'update' list. Also, you don't need to check if the list is empty to call update. It will only error if it is null.

6
  • Beat me to the punch! +1 for also moving out SOQL. – Adrian Larson Jun 3 '15 at 22:18
  • Haha, I knew this one was going to need some quick action... :) – Caspar Harmer Jun 3 '15 at 22:21
  • @CaspNZ thx for the help. but the processesToUpdate is actually meant to hold all the activities so is that redundant in this case? – saint Jun 3 '15 at 22:51
  • What you can do is create a second activity list and put the items you want to update into that. That will minimise your amount of records updated. I didn't do that for this example because you had already called the first list list processesToUpdate. If you do want to do this, put the Activity to be updated into your second update list as soon as you have changed the Actual_Date__c value. Then call update after your if statement. Oh and you can remove the processesToUpdate.size() check. – Caspar Harmer Jun 3 '15 at 22:58
  • 1
    ok have updated - there is an 'all' list and an 'update' list. However, both techniques will work - just the update version will have a lesser impact on the db. Also, you don't need to check if the list is empty to call update. It will only error if it is null. – Caspar Harmer Jun 3 '15 at 23:07

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.