SOQL and Child Records
A lot of posts regarding Apex coding focus on reducing down the number of SOQL statements you make during a Trigger.One way to achieve this which is recommended by David Liu on his blog is to:
- query all possible records
- build up a map to store all the query results
- when looping through the Trigger records, query against the map rather than the database each time
- perform a single update at the end of the Trigger - no matter how many records you are working with
Background
In a recent Trigger I also tried to reduce down the SOQL requirements even further by performing a sub query in the same statement. The official SOQL documentation can be found here.
The sub query brings back both the parent records and child records for an object in a single statement. For this project the SOQL sub query I created was:
Select id,name,CreatedById,NVMContactWorld__TimeStamp__c, NVMContactWorld__CallObjectIdentifier__c, (SELECT Name, CreatedById, CreatedDate, NVMContactWorld__Detail__c FROM NVMContactWorld__Interaction_Event_Notes__r) From NVMContactWorld__InteractionEvent__c ORDER BY NVMContactWorld__TimeStamp__c ASC NULLS FIRST
Bringing back these values in a single statement seemed like a time saver, but in order to query the child record values I had to
- set up a loop through all parent records
- set up an inner loop through all child records
The code to set up the 2 loops was:
for(NVMContactWorld__InteractionEvent__c acc:[Select id,name,CreatedById,NVMContactWorld__TimeStamp__c, NVMContactWorld__CallObjectIdentifier__c, (SELECT Name, CreatedById, CreatedDate, NVMContactWorld__Detail__c FROM NVMContactWorld__Interaction_Event_Notes__r) From NVMContactWorld__InteractionEvent__c ORDER BY NVMContactWorld__TimeStamp__c ASC NULLS FIRST]){ //System.debug('Outside of loop ' + acc.NVMContactWorld__CallObjectIdentifier__c); combinedNote = Null; //guid = Null; //Loop through child records for(NVMContactWorld__InteractionEventNote__c con:acc.NVMContactWorld__Interaction_Event_Notes__r){ //Perform updates on Child Records< } // end inner loop } // end outer loop
The TaskUpdate Trigger
TaskUpdate Trigger trigger TaskUpdate on Task (before insert, before update) { if (Trigger.isBefore && (Trigger.isInsert || Trigger.isUpdate)) TaskHelper.processTasks(Trigger.new); }
The TaskHelper Class
public with sharing class TaskHelper { public static void processTasks(List<Task> newTasks) { //Build a list of all users - make ID searchable List<User> users = [Select ID, FirstName, LastName, Name from User]; Map<String, User> allUsers = new Map<String, User>(); for (User a : users) { allUsers.put(a.ID, a); } System.debug('Size of allUsers is ' + allUsers.size()); //Build parent and child list of all Interaction Events and Interaction Notes Map<String, String> allNotes = new Map<String, String>(); List <NVMContactWorld__InteractionEventNote__c> conList = New List<NVMContactWorld__InteractionEventNote__c>(); String combinedNote; String guid; String newGuid; String oldGuid; for(NVMContactWorld__InteractionEvent__c acc:[Select id,name,CreatedById,NVMContactWorld__TimeStamp__c, NVMContactWorld__CallObjectIdentifier__c, (SELECT Name, CreatedById, CreatedDate, NVMContactWorld__Detail__c FROM NVMContactWorld__Interaction_Event_Notes__r) From NVMContactWorld__InteractionEvent__c ORDER BY NVMContactWorld__TimeStamp__c ASC NULLS FIRST]){ //System.debug('Outside of loop ' + acc.NVMContactWorld__CallObjectIdentifier__c); combinedNote = Null; //guid = Null; //Loop through child records for(NVMContactWorld__InteractionEventNote__c con:acc.NVMContactWorld__Interaction_Event_Notes__r){ //Change ID for real name User createdByName = allUsers.get(con.CreatedById); newGuid = acc.NVMContactWorld__CallObjectIdentifier__c; //System.debug('Debug element ' + con); //We need to merge single records into 1 String noteDetail; if (con.NVMContactWorld__Detail__c != Null) { //System.debug('This agent saved no notes'); noteDetail = con.NVMContactWorld__Detail__c; } else { noteDetail = 'This agent saved no notes'; } conList.add(con); //Create the actual string combinedNote = createdByName.Name + ' | on ' + con.CreatedDate + ' | ' + noteDetail + '\r\n'; guid = acc.NVMContactWorld__CallObjectIdentifier__c; if (allNotes.get(acc.NVMContactWorld__CallObjectIdentifier__c) == Null) { //System.debug('Map not created - create it'); allNotes.put(guid, combinedNote); } else { //System.debug('Map already created - update it'); String oldNotes = allNotes.get(acc.NVMContactWorld__CallObjectIdentifier__c); //System.debug('oldNotes is ' + oldNotes); allNotes.put(acc.NVMContactWorld__CallObjectIdentifier__c, oldNotes + ' \r\n' + combinedNote); //System.debug('allNotes is ' + allNotes.values()); } } //end outer for } //do we need to touch this record? Boolean validRecordsFound = false; System.debug('Starting class'); //Loop through Task records and get GUIDs to query Interaction Events - checking that it is only NVM Tasks for (Task ss : newTasks) { if (ss.CallType != Null && ss.CallObject != Null) { //We found a NVM task - there is work to do validRecordsFound = True; //Final call to the built map to populate description String oldValue = ss.Description; If (ss.Description == Null) { ss.Description = '\r\n--------Save your notes above this line--------\r\n' + allNotes.get(ss.CallObject); } else if (oldValue.contains('--------Save your notes above this line--------')) { Integer thingsToRemove = oldValue.indexOf('--------Save your notes above this line--------'); System.debug('Remove string after position ' + thingsToRemove); System.debug('Previous call notes found'); ss.Description = oldValue.left(thingsToRemove) + '\r\n--------Save your notes above this line--------\r\n' + allNotes.get(ss.CallObject); } else { String newValue = oldValue + '\r\n--------Save your notes above this line--------\r\n' + allNotes.get(ss.CallObject); ss.Description = newValue; } } //end if else { //System.debug('No work to do'); } } //end for } //end method } //end class
The Output
After all of that processing, the Trigger works through the child records attached to this parent record and populates a single field with all of their results.
Icon by Designmodo: from Iconfinder
Comments
Post a Comment