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
john4sfdcjohn4sfdc 

how to bulkify a trigger

Hi  all, I am a bit new to salesforce and i succesfully wrote this trigger. But i am lack of ideas on bulkifying it. The below trigger is a basic trigger to check if a contact is linked to a program or opportunity or account.

 

trigger CheckLinktoPrograms on Contact (after update,before delete) {

if(trigger.isupdate){
List<ProgramContactRole__c> lstConRole = new List<ProgramContactRole__c>();
List<AccountContactRole> lstConRole3 = new List<AccountContactRole>();
List<OpportunityContactRole> lstConRole4 = new List<OpportunityContactRole>();
Set<Id> setContactId = new Set<Id>();

for(Contact c:trigger.new){
setContactId.add(c.id);
}
lstConRole=[select id,name,ContactId__c,ProgramId__c,ProgramId__r.name from ProgramContactRole__c where ContactId__c IN:setContactId];
lstConRole3=[select id,ContactId,AccountId,Account.name from AccountContactRole where ContactId IN: setContactId];
lstConRole4=[select id,ContactId,OpportunityId,Opportunity.name from OpportunityContactRole where ContactId IN: setContactId];


for(integer i=0;i<trigger.new.size();i++){

  if(trigger.new[i].Active__c==false ){
 
 for(ProgramContactRole__c pcr:lstConRole){
   if(pcr.ContactId__c==trigger.new[i].id){
      trigger.new[0].addError('Cannot inactivate Contact if its linked to a Program: '+pcr.ProgramId__r.name);
   }
 }
 
 for(AccountContactRole acr:lstConRole3){
   if(acr.ContactId==trigger.new[i].id){
      trigger.new[0].addError('Cannot inactivate Contact if its linked to an Account: '+acr.Account.name);
   }
  }
 
  for(OpportunityContactRole ocr:lstConRole4){
   if(ocr.ContactId==trigger.new[i].id){
      trigger.new[0].addError('Cannot inactivate Contact if its linked to an Opportunity: '+ocr.Opportunity.name);
   }
  }
 
 }
 if(trigger.new[i].To_be_deleted__c == true){
 for(ProgramContactRole__c pcr:lstConRole){
   if(pcr.ContactId__c==trigger.new[i].id){
      trigger.new[0].addError('Cannot mark as delete if its linked to a Program: '+pcr.ProgramId__r.name);
   }
 }
 
 for(AccountContactRole acr:lstConRole3){
   if(acr.ContactId==trigger.new[i].id){
      trigger.new[0].addError('Cannot mark as delete if its linked to an Account: '+acr.Account.name);
   }
  }
 
  for(OpportunityContactRole ocr:lstConRole4){
   if(ocr.ContactId==trigger.new[i].id){
      trigger.new[0].addError('Cannot mark as delete if its linked to an Opportunity: '+ocr.Opportunity.name);
   }
  }
  }
}
}

if(trigger.isdelete){
List<AccountContactRole> lstConRole1 = new List<AccountContactRole>();
List<OpportunityContactRole> lstConRole2 = new List<OpportunityContactRole>();
Set<Id> setContactId = new Set<Id>();

for(Contact c:trigger.old){
 setContactId.add(c.id);

 }
lstConRole1=[select id,ContactId,AccountId,Account.name from AccountContactRole where ContactId IN: setContactId];
lstConRole2=[select id,ContactId,OpportunityId,Opportunity.name from OpportunityContactRole where ContactId IN: setContactId];

for(integer i=0;i<trigger.old.size();i++){

  for(AccountContactRole acr:lstConRole1){
    if(acr.ContactId==trigger.old[i].id){
    string accountname='<html><bold>';
    accountname+=acr.Account.name;
    accountname+='</body></html>';
     trigger.old[0].addError('Cannot delete Contact if its linked to an Account: '+accountname+' with a Role ( Contact Role ) ');
   }
  }
 
  for(OpportunityContactRole ocr:lstConRole2){
    if(ocr.ContactId==trigger.old[i].id){
     trigger.old[0].addError('Cannot delete Contact if its linked to an Opportunity: '+ocr.Opportunity.name+' with a Role ( Contact Role ) ');
   }
  }
 
 }
 
 
}


}

 
Best Answer chosen by Admin (Salesforce Developers) 
asish1989asish1989

I have checked casually only isupdate block,

here is some code you can refer.

trigger CheckLinktoPrograms on Contact (after update,before delete) {

	if(trigger.isupdate){
		List<ProgramContactRole__c> lstConRole = new List<ProgramContactRole__c>();
		List<AccountContactRole> lstConRole3 = new List<AccountContactRole>();
		List<OpportunityContactRole> lstConRole4 = new List<OpportunityContactRole>();
		
		// new varable for delete operation
		List<ProgramContactRole__c> lstConRoleForDelete = new List<ProgramContactRole__c>();
		List<AccountContactRole> lstConRole3ForDelete = new List<AccountContactRole>();
		List<OpportunityContactRole> lstConRole4ForDelete = new List<OpportunityContactRole>();
		Set<Id> setContactId = new Set<Id>();
		Set<Id> setContactIdForDelete = new Set<Id>();
		
		for(Contact c:trigger.new){
			if(c.Active__c == false)
				setContactId.add(c.id);
			if(c.To_be_deleted__c == true)	
				setContactIdForDelete.add(c.id);
		}
		lstConRole=[select id,name,ContactId__c,ProgramId__c,ProgramId__r.name from ProgramContactRole__c where ContactId__c IN:setContactId];
		lstConRole3=[select id,ContactId,AccountId,Account.name from AccountContactRole where ContactId IN: setContactId];
		lstConRole4=[select id,ContactId,OpportunityId,Opportunity.name from OpportunityContactRole where ContactId IN: setContactId];
		
		for(ProgramContactRole__c pcr:lstConRole){
			pcr.addError('Cannot inactivate Contact if its linked to a Program: '+pcr.ProgramId__r.name);
		}
		for(AccountContactRole acr:lstConRole3){
			acr.addError('Cannot inactivate Contact if its linked to an Account: '+acr.Account.name);
		}
		for(OpportunityContactRole ocr:lstConRole4){
			ocr.addError('Cannot inactivate Contact if its linked to an Opportunity: '+ocr.Opportunity.name);
		}
		
		// new query
		lstConRoleForDelete = [select id,name,ContactId__c,ProgramId__c,ProgramId__r.name from ProgramContactRole__c where ContactId__c IN:setContactIdForDelete];
		lstConRole3ForDelete =[select id,ContactId,AccountId,Account.name from AccountContactRole where ContactId IN: setContactIdForDelete];
		lstConRole4ForDelete =[select id,ContactId,OpportunityId,Opportunity.name from OpportunityContactRole where ContactId IN: setContactIdForDelete];
		
		for(ProgramContactRole__c pcr:lstConRoleForDelete){
			pcr.addError('Cannot mark as delete if its linked to a Program: '+pcr.ProgramId__r.name);
		}
		for(AccountContactRole acr:lstConRole3ForDelete){
			acr.addError('Cannot mark as delete if its linked to an Account: '+acr.Account.name);
		}
		for(OpportunityContactRole ocr:lstConRole4ForDelete){
			ocr.addError('Cannot mark as delete if its linked to an Opportunity: '+ocr.Opportunity.name);
		}
	}
	

 

All Answers

asish1989asish1989

I have checked casually only isupdate block,

here is some code you can refer.

trigger CheckLinktoPrograms on Contact (after update,before delete) {

	if(trigger.isupdate){
		List<ProgramContactRole__c> lstConRole = new List<ProgramContactRole__c>();
		List<AccountContactRole> lstConRole3 = new List<AccountContactRole>();
		List<OpportunityContactRole> lstConRole4 = new List<OpportunityContactRole>();
		
		// new varable for delete operation
		List<ProgramContactRole__c> lstConRoleForDelete = new List<ProgramContactRole__c>();
		List<AccountContactRole> lstConRole3ForDelete = new List<AccountContactRole>();
		List<OpportunityContactRole> lstConRole4ForDelete = new List<OpportunityContactRole>();
		Set<Id> setContactId = new Set<Id>();
		Set<Id> setContactIdForDelete = new Set<Id>();
		
		for(Contact c:trigger.new){
			if(c.Active__c == false)
				setContactId.add(c.id);
			if(c.To_be_deleted__c == true)	
				setContactIdForDelete.add(c.id);
		}
		lstConRole=[select id,name,ContactId__c,ProgramId__c,ProgramId__r.name from ProgramContactRole__c where ContactId__c IN:setContactId];
		lstConRole3=[select id,ContactId,AccountId,Account.name from AccountContactRole where ContactId IN: setContactId];
		lstConRole4=[select id,ContactId,OpportunityId,Opportunity.name from OpportunityContactRole where ContactId IN: setContactId];
		
		for(ProgramContactRole__c pcr:lstConRole){
			pcr.addError('Cannot inactivate Contact if its linked to a Program: '+pcr.ProgramId__r.name);
		}
		for(AccountContactRole acr:lstConRole3){
			acr.addError('Cannot inactivate Contact if its linked to an Account: '+acr.Account.name);
		}
		for(OpportunityContactRole ocr:lstConRole4){
			ocr.addError('Cannot inactivate Contact if its linked to an Opportunity: '+ocr.Opportunity.name);
		}
		
		// new query
		lstConRoleForDelete = [select id,name,ContactId__c,ProgramId__c,ProgramId__r.name from ProgramContactRole__c where ContactId__c IN:setContactIdForDelete];
		lstConRole3ForDelete =[select id,ContactId,AccountId,Account.name from AccountContactRole where ContactId IN: setContactIdForDelete];
		lstConRole4ForDelete =[select id,ContactId,OpportunityId,Opportunity.name from OpportunityContactRole where ContactId IN: setContactIdForDelete];
		
		for(ProgramContactRole__c pcr:lstConRoleForDelete){
			pcr.addError('Cannot mark as delete if its linked to a Program: '+pcr.ProgramId__r.name);
		}
		for(AccountContactRole acr:lstConRole3ForDelete){
			acr.addError('Cannot mark as delete if its linked to an Account: '+acr.Account.name);
		}
		for(OpportunityContactRole ocr:lstConRole4ForDelete){
			ocr.addError('Cannot mark as delete if its linked to an Opportunity: '+ocr.Opportunity.name);
		}
	}
	

 

This was selected as the best answer
john4sfdcjohn4sfdc

Hi Asish,

Thanks for posting the code. I keep getting the error message

Error:Apex trigger CheckLinktoPrograms caused an unexpected exception, contact your administrator: CheckLinktoPrograms: execution of AfterUpdate caused by: System.FinalException: SObject row does not allow errors: Trigger.CheckLinktoPrograms: line 41, column 1

 

when i try to update the To_be_deleted__c = true on my contact object

 

Any suggestions?

asish1989asish1989

Is it working fine when you are making Active = false?

john4sfdcjohn4sfdc

Hi Ashish,

It worked like a charm with few modifications. below is the modified code

 

trigger CheckLinktoPrograms on Contact (after update,before delete) {

    if(trigger.isupdate){
        List<ProgramContactRole__c> lstConRole = new List<ProgramContactRole__c>();
        List<AccountContactRole> lstConRole3 = new List<AccountContactRole>();
        List<OpportunityContactRole> lstConRole4 = new List<OpportunityContactRole>();
        
        // new varable for delete operation
        List<ProgramContactRole__c> lstConRoleForDelete = new List<ProgramContactRole__c>();
        List<AccountContactRole> lstConRole3ForDelete = new List<AccountContactRole>();
        List<OpportunityContactRole> lstConRole4ForDelete = new List<OpportunityContactRole>();
        Set<Id> setContactId = new Set<Id>();
        Set<Id> setContactIdForDelete = new Set<Id>();
        
        for(Contact c:trigger.new){
            if(c.Active__c == false)
                setContactId.add(c.id);
            if(c.To_be_deleted__c == true)  
                setContactIdForDelete.add(c.id);
        }
        lstConRole=[select id,name,ContactId__c,ProgramId__c,ProgramId__r.name from ProgramContactRole__c where ContactId__c IN:setContactId];
        lstConRole3=[select id,ContactId,AccountId,Account.name from AccountContactRole where ContactId IN: setContactId];
        lstConRole4=[select id,ContactId,OpportunityId,Opportunity.name from OpportunityContactRole where ContactId IN: setContactId];
        for(integer i=0;i<trigger.new.size();i++){
        for(ProgramContactRole__c pcr:lstConRole){
        if(pcr.ContactId__c == trigger.new[i].id){
           trigger.new[i].addError('Cannot inactivate Contact if its linked to a Program: '+pcr.ProgramId__r.name);
        }
        }
        for(AccountContactRole acr:lstConRole3){
        if(acr.ContactId == trigger.new[i].id){
           trigger.new[i].addError('Cannot inactivate Contact if its linked to an Account: '+acr.Account.name);
        }
        }
        for(OpportunityContactRole ocr:lstConRole4){
        if(ocr.ContactId == trigger.new[i].id){
           trigger.new[i].addError('Cannot inactivate Contact if its linked to an Opportunity: '+ocr.Opportunity.name);
        }
        }
        }
        
        // new query
        lstConRoleForDelete = [select id,name,ContactId__c,ProgramId__c,ProgramId__r.name from ProgramContactRole__c where ContactId__c IN:setContactIdForDelete];
        lstConRole3ForDelete =[select id,ContactId,AccountId,Account.name from AccountContactRole where ContactId IN: setContactIdForDelete];
        lstConRole4ForDelete =[select id,ContactId,OpportunityId,Opportunity.name from OpportunityContactRole where ContactId IN: setContactIdForDelete];
        for(integer i=0;i<trigger.new.size();i++){
        for(ProgramContactRole__c pcr:lstConRoleForDelete){
        if(pcr.ContactId__c == trigger.new[i].id){
            trigger.new[i].addError('Cannot mark as delete if its linked to a Program: '+pcr.ProgramId__r.name);
        }
        }
        
        for(AccountContactRole acr:lstConRole3ForDelete){
        if(acr.ContactId == trigger.new[i].id){
            trigger.new[i].addError('Cannot mark as delete if its linked to an Account: '+acr.Account.name);
        }
        }
        for(OpportunityContactRole ocr:lstConRole4ForDelete){
        if(ocr.ContactId == trigger.new[i].id){
            ocr.addError('Cannot mark as delete if its linked to an Opportunity: '+ocr.Opportunity.name);
        }
        }
        }
    }
    }

Team WorksTeam Works

Hi,

 

Could you please post the test class for this trigger as well...

 

Many Thanks!

 

asish1989asish1989

Hi

I am sharing some test code, you may need to modify some code.

@isTest
private class MileageTrackerTestSuite {

    static testMethod void runPositiveTestCases() {
	
		Account act = new Account();
		act.Name = 'test';
		insert act;
		
		Contact con = new Contact();
		con.LastName = 'test';
		con.Active__c = fasle;
		con.To_be_deleted__c = true;
		con.AccountId = act.id;
		insert con;
		
		ProgramContactRole__c pcRole = new ProgramContactRole__c();
		pcRole.ContactId__c = con.Id;
		pcRole.name = testrole;
		insert pcRole;
		
		AccountContactRole acRole = new AccountContactRole();
		acRole.ContactId = con.id;
		acRole.AccountId = act.id;
		insert acRole;
		
		Opportunity opt = new Opportunity()
		opt.Name = 'test';
		opt.StageName = 'IsClosed';
		opt.CloseDate = Date.Today();
		insert opt;
		
		OpportunityContactRole optRole = new OpportunityContactRole();
		optRole.ContactId = con.Id;
		optRole.OpportunityId = opt.Id;
		insert optRole;
		
		
		
		con.LastName = 'test2';
		upsert con;
	}
}	

 

Team WorksTeam Works

Hi Ashish,

 

Many Thanks for this code. I created this class and when i hit the Run Test Button for this class it display 0/1 test passed. But when i see in the debug log it correctly displays the expected custom error message as follows:

16:30:49.619 (619100000)|CODE_UNIT_FINISHED|CheckLinktoPrograms on Contact trigger event AfterUpdate for [0039000000RdDVv]
16:30:49.620 (620839000)|DML_END|[37]
16:30:49.620 (620936000)|EXCEPTION_THROWN|[37]|System.DmlException: Update failed. First exception on row 0 with id 0039000000RdDVvAAN; first error: FIELD_CUSTOM_VALIDATION_EXCEPTION, Cannot inactivate Contact if its linked to an Opportunity: test: []
16:30:49.621 (621676000)|HEAP_ALLOCATE|[37]|Bytes:187
16:30:49.621 (621736000)|FATAL_ERROR|System.DmlException: Update failed. First exception on row 0 with id 0039000000RdDVvAAN; first error: FIELD_CUSTOM_VALIDATION_EXCEPTION, Cannot inactivate Contact if its linked to an Opportunity: test: []

Class.MileageTrackerTestSuite.runPositiveTestCases: line 37, column 1
16:30:49.621 (621752000)|FATAL_ERROR|System.DmlException: Update failed. First exception on row 0 with id 0039000000RdDVvAAN; first error: FIELD_CUSTOM_VALIDATION_EXCEPTION, Cannot inactivate Contact if its linked to an Opportunity: test: []


Is it the correct way to HIT the Run Test Button to test the class?
asish1989asish1989

yes ,It is the correct way. After that you can see your trigger how much code is covered, 

When you click on run test button can you see the status is pass or fail,

If status is fail then there may be some exception so try to avoid that exceptions.

 

If everything is good then give kudos for my post which helps you

Team WorksTeam Works

Hi, 

Here is the output after hitting the Run Test.Also i can see 53% code coverage on the trigger.

Time Started 8/22/2013 5:16 PM Class MileageTrackerTestSuite Method Name runPositiveTestCases Pass/Fail Fail Error Message System.DmlException: Update failed. First exception on row 0 with id 0039000000RdDgGAAV; first error: FIELD_CUSTOM_VALIDATION_EXCEPTION, Cannot mark as delete if its linked to an Opportunity: test: [] Stack Trace

Class.MileageTrackerTestSuite.runPositiveTestCases: line 37, column 1

 

 

The Test is showing failed status because of the error message initiated from the trigger--custom error..

I am enhancing your code to do the negative test as well.

asish1989asish1989

Modify your test class or you can make  your validation rule which is on Contact I think as inacive.

 

Add these line to your test class 

Contact con1 = new Contact();
con1.LastName = 'testfinal';
con1.Active__c = fasle;
con1.To_be_deleted__c = true;
con1.AccountId = act.id;
insert con1;

 

modify these line 

con1.LastName = 'test2';
upsert con1;

 

Rest all are same.

Whatt we are doing here is we are just creating another conatct and updating that conat which is not linked to opportunity.

 

It is better you can make in active that rule for a while run the test class, after code coverage you can make it active