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
DUGLODUGLO 

Is this Apex Trigger properly bulkified?

Hi,

This is the first Apex trigger I've deployed into production. It creates a renewal opportunity when an original opportunity gets set to closed won. I'm looking for your feedback as to whether it is properly bulkified. When using the data loader I've run into some errors that suggests it's not. Here's a copy of the trigger: 
 
trigger CreateRenewalOppty on Opportunity (before update) {
    
    List<Opportunity> renewals = new List<Opportunity>();
    
    for (Opportunity opp : trigger.new) {
     Opportunity oldOpp = Trigger.oldMap.get(opp.Id);
        Boolean oldOppIsWon = oldOpp.StageName.equals('Closed Won');
        Boolean newOppIsWon = opp.StageName.equals('Closed Won');
        Date myDate = System.today();
        String acctName = [SELECT Account.Name
                          FROM Opportunity
                          WHERE ID IN: trigger.new
                          Limit 1].Account.Name;
        
        
                
        
        if (!oldOppIsWon &&
           newOppisWon &&
           helperClass.firstRun &&
           (opp.Business__c == 'Site' ||
            opp.Business__c == 'District')) {
                Opportunity renewal = new Opportunity();
                renewal.Name = acctName + ' ' + myDate.year() + '-1';
                renewal.CloseDate = opp.CloseDate + 365;
                renewal.StageName = 'Qualified Renewal';
                renewal.AccountId = opp.AccountId;
                renewal.Type = 'Renewal Business';
                renewal.Business__c = opp.Business__c;
               renewal.Term_Expiration_Date__c = opp.Term_Expiration_Date__c;
                renewal.Term_Start_Date__c = opp.Term_Start_Date__c;
                renewal.Primary_Contact_del__c = opp.Primary_Contact_del__c;
                renewal.Subscription_ID__c = opp.Subscription_ID__c;
                renewal.Amount = opp.Amount;
                renewal.Trigger_AM_Sequence__c = true;
                renewal.Notes__c = opp.Notes__c;
                renewal.Student_Username__c = opp.Student_Username__c;
                renewal.Area_of_Interest__c = opp.Area_of_Interest__c;
                renewal.Other_Area_of_Interest__c = opp.Other_Area_of_Interest__c;
                renewal.Postmortem_Notes__c = opp.Postmortem_Notes__c;
                renewal.Activation_Link__c = opp.Activation_Link__c;
                helperClass.firstRun = false;
                              
                
            renewals.add(renewal);
                
              
            }
         
    }
       System.debug('firstRun is ' + helperClass.firstRun);
            System.debug('The list contains ' + renewals.size() + ' opptys');
         try {
           insert renewals; 
         } catch (Exception e) {
           System.debug('Exception type caught ' + e.getTypeName());
         }


I followed the advice to add renewal opportunities to a list and then insert the list - so thought this meant the trigger was properly bulkified? Any other tips on how to improve this trigger would be greatly appreciated as well. Thanks!
FearNoneFearNone
put the query outside of loop:
String acctName = [SELECT Account.Name
                          FROM Opportunity
                          WHERE ID IN: trigger.new
                          Limit 1].Account.Name;
                                                    
for (Opportunity opp : trigger.new) {
...

 
hitesh90hitesh90
Hello Doug,

Following code is bulkified for your trigger. try that.
Apex Trigger:
trigger CreateRenewalOppty on Opportunity (before update) {
    
    List<Opportunity> renewals = new List<Opportunity>();
    String acctName = [SELECT Account.Name
                          FROM Opportunity
                          WHERE ID IN: trigger.new
                          Limit 1].Account.Name;
    List<Opportunity> oppList = [SELECT id, StageName, Business__c, Account.Name, CloseDate, AccountId, Amount,
                                    Term_Expiration_Date__c, Term_Start_Date__c, Primary_Contact_del__c, 
                                    Subscription_ID__c, Notes__c, Student_Username__c, Area_of_Interest__c, 
                                    Other_Area_of_Interest__c, Postmortem_Notes__c, Activation_Link__c
                                    FROM Opportunity 
                                    WHERE id in: trigger.newmap.keyset()];
    for (Opportunity opp : oppList) {
        Opportunity oldOpp = Trigger.oldMap.get(opp.Id);
        Boolean oldOppIsWon = oldOpp.StageName.equals('Closed Won');
        Boolean newOppIsWon = opp.StageName.equals('Closed Won');
        Date myDate = System.today();        
        if (!oldOppIsWon &&
           newOppisWon &&
           helperClass.firstRun &&
           (opp.Business__c == 'Site' ||
            opp.Business__c == 'District')) {
                Opportunity renewal = new Opportunity();
                renewal.Name = acctName + ' ' + myDate.year() + '-1';
                renewal.CloseDate = opp.CloseDate + 365;
                renewal.StageName = 'Qualified Renewal';
                renewal.AccountId = opp.AccountId;
                renewal.Type = 'Renewal Business';
                renewal.Business__c = opp.Business__c;
                renewal.Term_Expiration_Date__c = opp.Term_Expiration_Date__c;
                renewal.Term_Start_Date__c = opp.Term_Start_Date__c;
                renewal.Primary_Contact_del__c = opp.Primary_Contact_del__c;
                renewal.Subscription_ID__c = opp.Subscription_ID__c;
                renewal.Amount = opp.Amount;
                renewal.Trigger_AM_Sequence__c = true;
                renewal.Notes__c = opp.Notes__c;
                renewal.Student_Username__c = opp.Student_Username__c;
                renewal.Area_of_Interest__c = opp.Area_of_Interest__c;
                renewal.Other_Area_of_Interest__c = opp.Other_Area_of_Interest__c;
                renewal.Postmortem_Notes__c = opp.Postmortem_Notes__c;
                renewal.Activation_Link__c = opp.Activation_Link__c;
                helperClass.firstRun = false;              
                renewals.add(renewal);              
        }         
    }
    System.debug('firstRun is ' + helperClass.firstRun);
    System.debug('The list contains ' + renewals.size() + ' opptys');
    try {
        insert renewals; 
    } catch (Exception e) {
        System.debug('Exception type caught ' + e.getTypeName());
    }
 }

Let me know if you have any question on this. Please mark this "Solved" if it helps.

Thank You,
Hitesh Patel
ManojjenaManojjena
Hi Doug ,
try with below code it will help .If you will add LIMIT one in query it will not work in bulhk case .
 
trigger CreateRenewalOppty on Opportunity (before update) {
    if(helperClass.firstRun){
		List<Opportunity> renewals = new List<Opportunity>();
		Set<Id> accIdSet=new Set<Id>();
		Map<Id,Account> accMap;
		for (Opportunity opp : trigger.new) {
			if( helperClass.firstRun && Trigger.oldMap.get(opp.Id).stageName !=opp.stageName && opp.StageName.equals('Closed Won') && (opp.Business__c == 'Site' ||
				opp.Business__c == 'District') ){
				accIdSet.add(opp.AccountId);
		   
			}
		}
		if(!accIdSet.isEmpty()){
			accMap=new Map<Id,Account>([SELECT Id,Name FROM Account WHERE Id IN : accIdSet]);
		}
		if(!accMap.isEmpty()){
			for (Opportunity opp : trigger.new) {
				if( helperClass.firstRun && Trigger.oldMap.get(opp.Id).stageName !=opp.stageName && opp.StageName.equals('Closed Won') && (opp.Business__c == 'Site' ||
				opp.Business__c == 'District') ){
				   Opportunity renewal = new Opportunity();
					renewal.Name = accMap.get(opp.AccountId).Name + ' ' + System.Today().year() + '-1';
					renewal.CloseDate = opp.CloseDate + 365;
					renewal.StageName = 'Qualified Renewal';
					renewal.AccountId = opp.AccountId;
					renewal.Type = 'Renewal Business';
					renewal.Business__c = opp.Business__c;
					renewal.Term_Expiration_Date__c = opp.Term_Expiration_Date__c;
					renewal.Term_Start_Date__c = opp.Term_Start_Date__c;
					renewal.Primary_Contact_del__c = opp.Primary_Contact_del__c;
					renewal.Subscription_ID__c = opp.Subscription_ID__c;
					renewal.Amount = opp.Amount;
					renewal.Trigger_AM_Sequence__c = true;
					renewal.Notes__c = opp.Notes__c;
					renewal.Student_Username__c = opp.Student_Username__c;
					renewal.Area_of_Interest__c = opp.Area_of_Interest__c;
					renewal.Other_Area_of_Interest__c = opp.Other_Area_of_Interest__c;
					renewal.Postmortem_Notes__c = opp.Postmortem_Notes__c;
					renewal.Activation_Link__c = opp.Activation_Link__c;
					renewals.add(renewal);
				}
			} 
		}
		if(!renewals.isEmpty()){
		    try{
			    insert renewals;  
			}catch(DMLException de ){
			    System.debug(de.getMessage());
			}
		}
		 helperClass.firstRun = false;
    }
}
if you can create a formula field in opportunity to capture account Name then you can replace the code like  below .Replace  AccountName Formula with your field api name
trigger CreateRenewalOppty on Opportunity (before update) {
    if(helperClass.firstRun){
		List<Opportunity> renewals = new List<Opportunity>();
		for (Opportunity opp : trigger.new) {
			if( helperClass.firstRun && Trigger.oldMap.get(opp.Id).stageName !=opp.stageName && opp.StageName.equals('Closed Won') && (opp.Business__c == 'Site' ||
			opp.Business__c == 'District') ){
			   Opportunity renewal = new Opportunity();
				renewal.Name = opp.AccountName Formula + ' ' + System.Today().year() + '-1';
				renewal.CloseDate = opp.CloseDate + 365;
				renewal.StageName = 'Qualified Renewal';
				renewal.AccountId = opp.AccountId;
				renewal.Type = 'Renewal Business';
				renewal.Business__c = opp.Business__c;
				renewal.Term_Expiration_Date__c = opp.Term_Expiration_Date__c;
				renewal.Term_Start_Date__c = opp.Term_Start_Date__c;
				renewal.Primary_Contact_del__c = opp.Primary_Contact_del__c;
				renewal.Subscription_ID__c = opp.Subscription_ID__c;
				renewal.Amount = opp.Amount;
				renewal.Trigger_AM_Sequence__c = true;
				renewal.Notes__c = opp.Notes__c;
				renewal.Student_Username__c = opp.Student_Username__c;
				renewal.Area_of_Interest__c = opp.Area_of_Interest__c;
				renewal.Other_Area_of_Interest__c = opp.Other_Area_of_Interest__c;
				renewal.Postmortem_Notes__c = opp.Postmortem_Notes__c;
				renewal.Activation_Link__c = opp.Activation_Link__c;
				renewals.add(renewal);
			}
		} 
		if(!renewals.isEmpty()){
		    try{
			    insert renewals;  
			}catch(DMLException de ){
			    System.debug(de.getMessage());
			}
		}
		 helperClass.firstRun = false;
    }
}
Let me know if it helps !!
Thanks
Manoj