function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Andrew GAndrew G 

persist list in trigger

Hi
I'm playing with an Apex trigger for Work Order Object.   In the trigger,I have a need to reference a list of Work Types on multiple occassions, in different parts of the trigger.  The question relates to how do I minimise the number of times I do a SOQL to get those work types.
Example of Trigger
trigger cs_workorderTrigger on WorkOrder (before insert, after insert, after update) {
    if ( trigger.isBefore ) {
        if ( trigger.isInsert ) {
            CS_WorkOrderTriggerHandler.handleBeforeInsert( trigger.new );
	}
    } else {  //trigger is after
        if ( trigger.isInsert ) {
            CS_WorkOrderTriggerHandler.handleAfterInsert( trigger.new );
        } else {
            CS_WorkOrderTriggerHandler.handleAfterUpdate( trigger.new );
	}
    }
}
And my (cut down) hanlder looks like:
public with sharing class CS_WorkOrderTriggerHandler {
			
	public static void handleBeforeInsert(List<WorkOrder> newWorkOrders) {
		populateWorkOrder( newWorkOrders );
	}

	public static void handleAfterInsert(List<WorkOrder> workOrders){
		//declare some variables 
		List<Id> listWorkTypeIds = new List<Id>();

		//List of Ids where their is an auto generate feature enabled
		List<Worktype> workTypes = new List<WorkType>([SELECT Id FROM WorkType WHERE ShouldAutoCreateSvcAppt = TRUE]);

		for ( WorkOrder workOrder : workOrders ) {
			//do some stuff with work Order - like checking the work type Id
		}
	}


	public static void handleAfterUpdate(List<WorkOrder> oldWorkOrders, List<WorkOrder> workOrders, Map<Id,WorkOrder> newValues, Map<Id,WorkOrder> oldValues) {
		//declare some variables 
		List<Id> listWorkTypeIds = new List<Id>();

		//List of Ids where their is an auto generate feature enabled - HEY , THIS IS THE SAME AS THE AFTER INSERT QUERY

		for ( WorkOrder workOrder : workOrders ) {
			//do some other stuff with the work orders, and I still need the work type ids, but this work here is different to the after Insert stuff so i can't combine into a single method.
		}
	}

	public static void populateWorkOrder(List<WorkOrder>workOrders) {
		System.debug('DEBUG: populate Work Order');
		//Here I am going to do some other stuff, and I need that slightly different list of that Work Type Ids
		//something like 
		List<workType> workTypes = new List<WorkType>([SELECT Id,Customer_Type__c,Name FROM WorkType WHERE ShouldAutoCreateSvcAppt = TRUE]);
		//and play with the list a bit differently
	}

	public static void createServiceAppointments(WorkOrder workOrder, Integer saToCreate ) {
		//Create some records here
	}
	
}

I tried doing a constructor at the top of the trigger handler, but I was getting errors like "non static method can be called form static method" or something like that.  It basically broke the other methods I have within the trigger handler.

Any pointers appreciated.

Andrew G
Banwari KevatBanwari Kevat
Hi Andrew,
   Create map of WorkType. After that you can get the WorkType from method without SOQL.

Thanks
Banwari
Meghna Vijay 7Meghna Vijay 7
Hi Andrew,
trigger cs_workorderTrigger on WorkOrder (before insert, after insert, after update) {
    if ( trigger.isBefore ) {
        // There is no need to use BeforeInsert if you are creating/updating workOrderType 
       // record. 
        if ( trigger.isInsert ) {
            CS_WorkOrderTriggerHandler.handleBeforeInsert( trigger.new );
	}
    } else {  //trigger is after
        if ( trigger.isInsert ) {
            CS_WorkOrderTriggerHandler.handleAfterInsert( trigger.new );
        } else {
            // Update method will run only when there is a change in workorderTypeId of 
             //workorders otherwise it won't . Why I added it ? Because you don't want to call 
               it 
             //everytime there is a change in any of the fields on that record.
            CS_WorkOrderTriggerHandler.handleAfterUpdate( trigger.new, trigger.oldMap ); 
	}
    }
}

public static void handleAfterInsert(List<WorkOrder> workOrders) {
    Set<Id> workOrderTypeIdSet = new Set<Id>();
   // You'll want only those workordertype which are related to the inserted/updated Work 
   //Order Records. Start 
    for(WorkOrder workOrder : workOrders) {
      if(workOrder.WorkOrderTypeId !=null) {
        workOrderTypeIdSet.add(workOrder.WorkOrderTypeId);
      }
   }
   // End
   if(workOrderTypeIdSet.size()>0) {
     populateWorkOrder(workOrderTypeIdSet);
}    
}

public static void handleAfterUpdate(List<WorkOrder> workOrders, Map<Id,WorkOrder> oldMap) {
    Set<Id> workOrderTypeIdSet = new Set<Id>();
// You'll want only those workordertype which are related to the inserted/updated Work //Order Records. Start 
    for(WorkOrder workOrder : workOrders) {
      if(workOrder.WorkOrderTypeId != oldMap.get(workOrder.Id).WorkOrderTyeId ) {
        workOrderTypeIdSet.add(workOrder.WorkOrderTypeId);
}
}
// End
populateWorkOrder(workOrderTypeIdSet);
}

public static void populateWorkOrder(Set<Id> workOrderTypeIdSet) {
		//something like 
		List<workType> workTypes = new List<WorkType>([SELECT Id,Customer_Type__c,Name FROM WorkType WHERE ShouldAutoCreateSvcAppt = TRUE AND Id IN: workOrderTypeIdSet]);

Or you can create a map like :-
Map<Id, WorkOrderType> workOrderTypeMap = new Map<Id,WorkOrderType>([SELECT Id,Customer_Type__c,Name FROM WorkType WHERE ShouldAutoCreateSvcAppt = TRUE AND Id IN: workOrderTypeIdSet]);

		//and play with the list a bit differently
	}

 
Andrew GAndrew G
Thank you both for your responses.

@ Banwari - yes, i have been using the Maps, they are just not shown in the cut down version of the Handler - I didn't think people would want to read the full 250 odd lines.

@ Meghna - some interesting comments and ideas.  However, I do want the work types before I do the Insert as well as after.

Work Order is an object with a relation to Work Type object.  
Before I do the insert, I want to actual change the Work Type on the Work Order based on some parameters, so i need all the work types as I don't know which one I will use in the Work Order before I Insert.
After the insert, I need to Work Types as I will use the AutoCreate Flag as a decision point in how I create the Service Appointments.  Here I could use your idea to limit the number of Work Types return by building a list of the work orders inserted.

I suppose my question could be modified to 

IF I am to query Work Types in both the Before Insert and After Insert, should I be worried about doing the 2 x SOQL queries for essentially the same data?  Or is the fact that the queries are outside any loops, therefore I have addressed bulkification of the trigger?


As I sit here this morning, a bit clearer of head, I think I know the answer.  I think I was muddled by the fact that a couple of my test methods was inserting and updating in the same method and therefore causing all the SOQLs to fire across the trigger, and I become concerned about limits.


Regards
Andrew