+ Start a Discussion
mgodseymgodsey 

Help bulkifying a trigger

I have a trigger that is working the way I want it to, but it's not bulkified. If someone could help me figure out how to move the SOQL query out of the for loop I would really appreciate it! This trigger is on the OpportunityTeamMember object. When one team member is added, a field on the Opp should update to "Yes" and if a team member is deleted and there will not be any remaining team members after deletion, the field on the Opp should update to "No." 

 

  //------------------------------------------Before Delete----------------------------------------

    if(Trigger.isBefore && Trigger.isDelete){
    
        //create collections to store 1) IDs for Opportunities for deleted team member(s), 2) Actual Opportunity records with deleted Team Members, 3) Opps that will need to be updatead to say "No" not a Shared Opportunity
        Set<Id> oppIDs = new Set<ID>();
        List<Opportunity> oppsWithDeletedTeamMembers = new List<Opportunity>();
        List<Opportunity> oppsToUpdate = new List<Opportunity>();
        
    
        //loop through deleted team members and add their Opportunities to the list above
        for (OpportunityTeamMember deletedTM : trigger.old){
            oppIDS.add(deletedTM.OpportunityID);
            system.debug('[MF Debug] Opportunity field from deleted Team Member = ' + deletedTM.OpportunityID);
        }
        
        oppsWithDeletedTeamMembers = [SELECT Id FROM Opportunity WHERE id =: oppIDs];
        system.debug('[MF DEBUG] Opps with Deleted Team Member = ' + oppsWithDeletedTeamMembers);
        
        /*
        *Loop through the Opportunities in the OppsWithDeleteTeamMembers list and see how many team members pre-deletion. 
        *If it's less than or equal to 1, the Opp will no longer be considered shared after that team member is deleted.
        */
        for (Opportunity opp : oppsWithDeletedTeamMembers){
            List<OpportunityTeamMember> currentTeamMembers = [SELECT ID FROM OpportunityTeamMember WHERE OpportunityID =: opp.ID];
            Integer currentTeamMemberCount = currentTeamMembers.size();
            system.debug('[MF DEBUG] currentTeamMemberCount = :' + currentTeamMemberCount);
            
            if(currentTeamMemberCount <= 1){
                opp.SharedOpportunity__c = 'NO';
                oppsToUpdate.add(opp);
            }
        }
               
        update OppsToUpdate;
            
    }

 

Best Answer chosen by Admin (Salesforce Developers) 
s_k_as_k_a

Here is the trigger code and apexclass for opportunityteammember  bulk delete, update and  insert

 

Apex class for trigger

 

public with sharing class updateOppforTeammembers
{
	public static void processOpportunityTeamMembers (List<OpportunityTeamMember> opptms){

		Set<Id> oppIds = new Set<Id>();
		for(OpportunityTeamMember otm: opptms)
		{
			oppIds.add(otm.Opportunity);
		}
		
		Map<Id, List<OpportunityTeamMember>> oppToOppTeamMems = new Map<Id, List<OpportunityTeamMember>>();
		for(OpportunityTeamMember  tm :[SELECT ID FROM OpportunityTeamMember WHERE OpportunityID in : oppIds])
		{
		   if(oppToOppTeamMems.containsKey(tm.opportunity) && oppToOppTeamMems.get(tm.opportunity) != null)
			{
				List<OpportunityTeamMember>  tempTeamMems = new List<OpportunityTeamMember>();
				tempTeamMems = oppToOppTeamMems.get(tm.opportunity);
				tempTeamMems.add(tm);
			}else
				oppToOppTeamMems.put(tm.opportunity, new List<OpportunityTeamMember>{tm});
		}

		List<opportunity> oppUpadateList = new List<opportunity>();
		for(opportunity opp : [Select Id, SharedOpportunity__c from opportunity where id in : oppIds])
		{
			if(oppToOppTeamMems.containsKey(opp.id))
			{
				if(oppToOppTeamMems.get(opp.id).size() >0)
					opp.SharedOpportunity__c = 'YES';
				else
					opp.SharedOpportunity__c = 'NO';
			}
		}
	}
}

 triger on opportunityteammember

trigger updateOppforTeammembersTrigger on OpportunityTeamMember (after delete, after insert, after update) {
      
  // fires after both insert and update
  if((Trigger.isInsert || Trigger.isUpdate) && Trigger.isAfter)
  {    
     updateOppforTeammembers.processOpportunityTeamMembers(Trigger.new);
  // fires when records are deleted. 
  }else if(Trigger.isDelete && Trigger.isAfter){
    
    updateOppforTeammembers.processOpportunityTeamMembers(Trigger.old);
  }

}

 

All Answers

s_k_as_k_a

Here is the trigger code and apexclass for opportunityteammember  bulk delete, update and  insert

 

Apex class for trigger

 

public with sharing class updateOppforTeammembers
{
	public static void processOpportunityTeamMembers (List<OpportunityTeamMember> opptms){

		Set<Id> oppIds = new Set<Id>();
		for(OpportunityTeamMember otm: opptms)
		{
			oppIds.add(otm.Opportunity);
		}
		
		Map<Id, List<OpportunityTeamMember>> oppToOppTeamMems = new Map<Id, List<OpportunityTeamMember>>();
		for(OpportunityTeamMember  tm :[SELECT ID FROM OpportunityTeamMember WHERE OpportunityID in : oppIds])
		{
		   if(oppToOppTeamMems.containsKey(tm.opportunity) && oppToOppTeamMems.get(tm.opportunity) != null)
			{
				List<OpportunityTeamMember>  tempTeamMems = new List<OpportunityTeamMember>();
				tempTeamMems = oppToOppTeamMems.get(tm.opportunity);
				tempTeamMems.add(tm);
			}else
				oppToOppTeamMems.put(tm.opportunity, new List<OpportunityTeamMember>{tm});
		}

		List<opportunity> oppUpadateList = new List<opportunity>();
		for(opportunity opp : [Select Id, SharedOpportunity__c from opportunity where id in : oppIds])
		{
			if(oppToOppTeamMems.containsKey(opp.id))
			{
				if(oppToOppTeamMems.get(opp.id).size() >0)
					opp.SharedOpportunity__c = 'YES';
				else
					opp.SharedOpportunity__c = 'NO';
			}
		}
	}
}

 triger on opportunityteammember

trigger updateOppforTeammembersTrigger on OpportunityTeamMember (after delete, after insert, after update) {
      
  // fires after both insert and update
  if((Trigger.isInsert || Trigger.isUpdate) && Trigger.isAfter)
  {    
     updateOppforTeammembers.processOpportunityTeamMembers(Trigger.new);
  // fires when records are deleted. 
  }else if(Trigger.isDelete && Trigger.isAfter){
    
    updateOppforTeammembers.processOpportunityTeamMembers(Trigger.old);
  }

}

 

This was selected as the best answer
mgodseymgodsey

Thank you for your help. I understand most of the class, but I'm unsure as to why we are creating the tempTeamMems list. Do you mind explaining why that is included? Thank you so much!

s_k_as_k_a

 

Let say one opporunity has three opportunityTeamMember records.

 

for loop wiil execute each time for each opportunityTeamMember record.

 

step 1: First oppteammember record enters into for loop, if condition checks the opportunityId of team member is aleredy added to map key value or not. Because of first oppteam record the map does not contain key- value an opportunityId of team record. so both opportunityId and team record will added to map . in this step list in map contains only one team record.

 

When the second team record of same opportunity enter into the for loop,it will check first the map containd this opportunityid or not. If map already contains opportunity Id means , we will collect already added team record into a list  add the new one we will add to that list and the total list added to map. In this step list in map contains two team records.

 

Similery for third record.

 

s_k_as_k_a

Add this line  in your code below

 

 tempTeamMems.add(tm);

oppToOppTeamMems.put(tm.oppotunityId, tempTeamMems);

mgodseymgodsey

Thank you so much for your help. I had to make a few tweaks, but now it's working when I test in bulk in my unit test!