+ Start a Discussion
ekorzekorz 

Bulkify trigger by moving the SOQL query

I've been staring at the Salesforce bulkify best practice pages for like an hour, and it's just not happening for me. 

 

I have 2 custom objects, Supply and Shipment.  They're related through a lookup field, namely Supplies__c.Shipment__c.  But, my warehouse doesn't have access to the SFID's, so they're recording the "Tracking" numbers instead -- a unique identifier.  At the end of the day, I upload a list of those tracking numbers onto Supplies__c.Tracking__c and built this trigger to update the Supplies__c.Shipment__c  lookup field automatically. 

 

This trigger code queries all the Shipments, finds the one that has the tracking number in question, and updates the Supply record's lookup field with the Shipment__c.id.  Works great!  But, it blows up in bulk because of the query inside the for() loop.

 

Trigger GrabLocationFromShipment on Supplies__c (before insert, before update) {
  for (Supplies__c  s: trigger.new) {
    if(s.Tracking__c != null) {
       List<Shipment__c> ship = new List<Shipment__c>();
ship = [Select Id from Shipment__c WHERE Shipment__c.Tracking__c = :s.Tracking__c LIMIT 1]; if (ship.size() > 0){
s.Shipment__c = ship[0].Id; } } } }

 

How do I run this query outside the for() loop, and still return the matching IDs so I can update the lookup?

Best Answer chosen by Admin (Salesforce Developers) 
Saikishore Reddy AengareddySaikishore Reddy Aengareddy

Try this..

 

Trigger GrabLocationFromShipment on Supplies__c (before insert, before update) {
	
	set<string> trackingIds = new set<string>();
	
	Map<string,Id> shipmentMap = new Map<string,Id>();
  
    for (Supplies__c  s: trigger.new) {
		if(s.Tracking__c != null) {
			trackingIds.add(s.Tracking__c);
		}
    }	
	for(shipment__c s : [Select Id,Tracking__c from Shipment__c WHERE Shipment__c.Tracking__c IN :trackingIds]){
		shipmentMap.put(s.Tracking__c,s.Id);
	}
	
	for (Supplies__c  s: trigger.new) {
		if(s.Tracking__c != null && shipmentMap.containskey(s.Tracking__c)){
			s.shipment__c = shipmentmap.get(s.Tracking__c);
		}
	}
	
}

 

All Answers

Saikishore Reddy AengareddySaikishore Reddy Aengareddy

Try this..

 

Trigger GrabLocationFromShipment on Supplies__c (before insert, before update) {
	
	set<string> trackingIds = new set<string>();
	
	Map<string,Id> shipmentMap = new Map<string,Id>();
  
    for (Supplies__c  s: trigger.new) {
		if(s.Tracking__c != null) {
			trackingIds.add(s.Tracking__c);
		}
    }	
	for(shipment__c s : [Select Id,Tracking__c from Shipment__c WHERE Shipment__c.Tracking__c IN :trackingIds]){
		shipmentMap.put(s.Tracking__c,s.Id);
	}
	
	for (Supplies__c  s: trigger.new) {
		if(s.Tracking__c != null && shipmentMap.containskey(s.Tracking__c)){
			s.shipment__c = shipmentmap.get(s.Tracking__c);
		}
	}
	
}

 

This was selected as the best answer
ekorzekorz

Thanks, that worked!  That was fast, also, I appreciate it.

 

If I want to grab another field off the Shipment, should I set up another Map?

 

 

 

Saikishore Reddy AengareddySaikishore Reddy Aengareddy

I would recommend updating the map<string,Id> to map<string,shipment__c>

 

Here is the code

 

Trigger GrabLocationFromShipment on Supplies__c (before insert, before update) {

set<string> trackingIds = new set<string>();

Map<string,shipment__c> shipmentMap = new Map<string,shipment__c>();

for (Supplies__c s: trigger.new) {
if(s.Tracking__c != null) {
trackingIds.add(s.Tracking__c);
}
}
for(shipment__c s : [Select Id,Tracking__c,anotherField__c from Shipment__c WHERE Shipment__c.Tracking__c IN :trackingIds]){
shipmentMap.put(s.Tracking__c,s);
}

for (Supplies__c s: trigger.new) {
if(s.Tracking__c != null && shipmentMap.containskey(s.Tracking__c)){
s.shipment__c = shipmentmap.get(s.Tracking__c).Id;
}
}

}