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
Mona WesoMona Weso 

How do I bulkify this trigger?

I created this trigger to update a related opportunity when an OpportunityContactRole not marked as Primary is created.  I am updating two lookup fields with OpportunityContactRole.ContactId on the opportunity -- if one field (secondaryclient) already contains a value, then the next field (tertiaryclient) should be updated if null.  If both fields on the opportunity already contain a value, then no updates should be made.  It currently functions as expected, but it needs some work to bulkify. How can I do this?

trigger NonPrimaryClientTrigger on OpportunityContactRole (before insert) {

    if (ByPassSettingTriggers__c.getInstance().OpportunityContactRole__c) {        
        return;
    }

    //Adding it to track the start of trigger execution
    System.debug('Start of OpportunityContactRole Trigger, operation type : '+trigger.operationType+' , Start Time: '+System.now()+' , CPU Time Start: '+Limits.getCpuTime());
     
    //Allows the trigger to only execute if the OpportunityContactRole added is nonPrimary
    Set<Id> ids = new Set<Id>();
        for (OpportunityContactRole ocr : Trigger.new){
            if (ocr.IsPrimary == False){
                ids.add(ocr.Id);
                }            
        
    System.debug('OCR Id list size = ' + ids.size());
    if (ids.size() > 0) {
     
    //Get Opportunity Ids of all Opportunities related to nonPrimary OpportunityContactRoles
        List<Id> oppIds = new List<Id>();
            for (OpportunityContactRole ocrs:Trigger.new){                
                    oppIds.add(ocrs.OpportunityId);         
                }

    System.debug('OpportunityID list after OpportunityContactRole Loop' + oppIds);
    
    List<Opportunity> oppList = [SELECT Id, SecondaryClient__c, TertiaryClient__c FROM Opportunity WHERE TertiaryClient__c = Null AND Id IN :oppIds];
       
        for(Opportunity opp :oppList){
    
    //If there is no SecondaryClient, then add the Contact Id to this field
                if (opp.SecondaryClient__c == Null) {
                    opp.SecondaryClient__c = ocr.ContactId;
                }   
    //If there is already a SecondaryClient, then add the Contact Id to the TertiaryClient field     
                    else
                    {
                        if(opp.SecondaryCLient__c != Null && opp.TertiaryClient__c == Null){
                        opp.TertiaryClient__c = ocr.ContactId;
                        }
                    }
                }     
        
        update oppList;    
    }
}
ANUTEJANUTEJ (Salesforce Developers) 
Hi Mona,

>> https://www.sfdc99.com/2014/01/18/bulkifying-code/

>> https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_triggers_bulk_idioms.htm

The above two links have the details in regards to bulkifying the trigger you can check it once.

I would suggest you to use the trigger.isbefore and trigger.isinsert to run the trigger snippet only on before insert condition, so your code would be something like below:
 
trigger NonPrimaryClientTrigger on OpportunityContactRole (before insert) {

   if(trigger.isbefore && trigger.isinsert)
{
 if (ByPassSettingTriggers__c.getInstance().OpportunityContactRole__c) {        
        return;
    }

    //Adding it to track the start of trigger execution
    System.debug('Start of OpportunityContactRole Trigger, operation type : '+trigger.operationType+' , Start Time: '+System.now()+' , CPU Time Start: '+Limits.getCpuTime());
     
    //Allows the trigger to only execute if the OpportunityContactRole added is nonPrimary
    Set<Id> ids = new Set<Id>();
        for (OpportunityContactRole ocr : Trigger.new){
            if (ocr.IsPrimary == False){
                ids.add(ocr.Id);
                }            
        
    System.debug('OCR Id list size = ' + ids.size());
    if (ids.size() > 0) {
     
    //Get Opportunity Ids of all Opportunities related to nonPrimary OpportunityContactRoles
        List<Id> oppIds = new List<Id>();
            for (OpportunityContactRole ocrs:Trigger.new){                
                    oppIds.add(ocrs.OpportunityId);         
                }

    System.debug('OpportunityID list after OpportunityContactRole Loop' + oppIds);
    
    List<Opportunity> oppList = [SELECT Id, SecondaryClient__c, TertiaryClient__c FROM Opportunity WHERE TertiaryClient__c = Null AND Id IN :oppIds];
       
        for(Opportunity opp :oppList){
    
    //If there is no SecondaryClient, then add the Contact Id to this field
                if (opp.SecondaryClient__c == Null) {
                    opp.SecondaryClient__c = ocr.ContactId;
                }   
    //If there is already a SecondaryClient, then add the Contact Id to the TertiaryClient field     
                    else
                    {
                        if(opp.SecondaryCLient__c != Null && opp.TertiaryClient__c == Null){
                        opp.TertiaryClient__c = ocr.ContactId;
                        }
                    }
                }     
        
        update oppList;    
    }
}
}

Let me know if it helps you and close your query by marking it as the best answer so that it can help others in the future.  

Thanks.
Maharajan CMaharajan C
Hi Mona,

Please try the below trigger:
 
trigger NonPrimaryClientTrigger on OpportunityContactRole (after insert) {

    if (ByPassSettingTriggers__c.getInstance().OpportunityContactRole__c) {        
        return;
    }

    //Adding it to track the start of trigger execution
    System.debug('Start of OpportunityContactRole Trigger, operation type : '+trigger.operationType+' , Start Time: '+System.now()+' , CPU Time Start: '+Limits.getCpuTime());
     
	List<Opportunity> oppListtoUpdate = new List<Opportunity>();
	
	Set<Id> ids = new Set<Id>();
	for (OpportunityContactRole ocr : Trigger.new){
		if (ocr.IsPrimary == False){
			ids.add(ocr.Id);
		} 
	}		
        
    if (ids.size() > 0) {
        
		for(OpportunityContactRole ocrRec : [SELECT Id,IsPrimary,ContactId,Opportunity.SecondaryClient__c,Opportunity.TertiaryClient__c,OpportunityId from OpportunityContactRole where Id IN: ids ]){
			if (ocrRec.Opportunity.SecondaryClient__c == Null) {
				Opportunity opp = new Opportunity(Id = ocrRec.OpportunityId);
				opp.SecondaryClient__c = ocrRec.ContactId;
				oppListtoUpdate.add(opp);
			} 
			else if(ocrRec.Opportunity.SecondaryCLient__c != Null && ocrRec.Opportunity.TertiaryClient__c == Null){
				Opportunity opp = new Opportunity(Id = ocrRec.OpportunityId);
				opp.TertiaryClient__c = ocrRec.ContactId;
				oppListtoUpdate.add(opp);
			}
		}  
		
		if(!oppListtoUpdate.IsEmpty())
			update oppListtoUpdate;    
    }
}

1. Please use the after insert trigger.
2. Don't use the Soql inside for loop.
3. Don't use the Dml inside for loop.
4. Don't extent the for loop. Use Collections or SOQL with parent data for above points.


Thanks,
Maharajan.C