feed-icon-32x32.png

Learn how Salesforce.com can help your business
arrowpointe @ twitter
  • iphone vs. bold, iphone vs. bold,. i can't decide! iphone's keyboard scares me. Bold's OTA Google Calendar sync is very useful. :( 1 day ago
  • looking to talk to someone that's called Apex WebServices from PHP. have specific questions. 2 days ago
  • is anyone clear on pricing for authenticated users? is it free and all pricing is page view based? 2 days ago
  • got demo of Avankia's Credit Card Processing in Salesforce.com. Nice product. Better stuff on the way. http://tinyurl.com/5wsrq5 1 week ago
  • downloading my first album from Amazon MP3 store. I like it! I chose Car Alarm by The Sea and Cake (great band). 1 week ago
  • in things that are not marketing campaigns, what's your strategy of using Tags vs. Campaigns in Salesforce? 2 weeks ago
  • going to try youmail.com for my voicemail 2 weeks ago
  • More updates...

Powered by Twitter Tools.



Bulkifying a Trigger (an example)

Back in June, I blogged about a trigger I made to auto-create a Campaign Member record for new Leads if the Lead Source value matched the Name of an existing Campaign.  Steve Andersen rightfully commented on that post about the need to bulkify the trigger.  I have been pretty slow in learning Apex and over the past week or so things have started clicking for me.  I am now (finally) beginning to “get it”.  With the help of Matt Kaufman and a friend at Salesforce, I have come to understand Apex a bit more and can much more easily apply it to my day to day Salesforce work.

Therefore, I thought I should correct the trigger I wrote and make it bulkified.  This should serve as a good before and after example of a trigger that accomplishes the same thing, but is now bulkified.

The original Trigger
Below is how the trigger looked originally.

trigger Create_CampaignMember_For_New_Leads on Lead (after insert) {

	try {	

		if (Trigger.new.size() == 1) {

			List <CampaignMember> cm = new list<CampaignMember>();

			for(Lead L : Trigger.new) {

					String cname = L.leadsource;

					// Added for AppExchange Partners that get leads via AppExchange where Salesforce added the "dup-" term to signify a duplicate
					String replaceText2 = 'dup-';
					cname = cname.replace(replaceText2,'');

					List <Campaign> c = [select id, name from Campaign where name = :cname limit 1];

					if(!c.isEmpty()){
						CampaignMember cml = new CampaignMember();
						cml.campaignid = c[0].id;
						cml.leadid = l.id;
						cm.add(cml);
					}
			}

			if(!cm.isEmpty()){
				insert cm;
			}
		}

	} catch(Exception e) {
		system.debug ('error: ' + e.getMessage() );
	}
}

Bulkified Trigger
And now a corrected version to be bulkified.

trigger Create_CampaignMember_For_New_Leads on Lead (after insert) {

	/*
    * Loop through all leads and collect the necessary lists
    */
	list<Lead> theLeads = new list<Lead>(); // List containing each Lead being processed
	list<String> cNames = new list<String>(); // List of Campaign Names
	map<String, String> map_lSource_to_cName = new map<String, String>(); // Mapping Lead Sources to Campaign Names. We have this because we are cleaning up Lead Sources in some cases.
	String wrkText = ''; // Temporary, working variable
	String replaceText = 'dup-'; // Text to replace. This is included for ISV partners who want to remove the "-dup" string that is included for duplicate AppExchange Lead Submissions  

		for(Lead l:trigger.new) {
			theLeads.add(l); // add lead to the main lead list
			if (l.leadsource != null) {
				wrkText = l.leadsource;
				wrkText = wrkText.replace(replaceText,'');
				cNames.add(wrkText); // add to list of Campaign Names
				map_lSource_to_cName.put(l.leadsource,wrkText); // add to map of Lead Sources to Campaign Names
			}
		}

	/*
	* Create a map containing an association of Campaign Names to Campaign IDs
	*/
	list<Campaign> theCampaigns = [SELECT Id, Name FROM Campaign WHERE Name IN :cNames]; // Campaign sObjects we are dealing with
	map<String, ID> map_cName_to_cID = new map<String, ID>(); // Mapping Campaign Names to Campaign IDs

		for (Campaign c:theCampaigns) {
			map_cName_to_cID.put(c.Name,c.Id);
		}

	/*
	* Loop through the main list of Leads
	*/
	list <CampaignMember> theCampaignMembers = new list<CampaignMember>(); // List containing Campaign Member records to be inserted

	for (Lead l:theLeads) {
		if(map_cName_to_cID.get(map_lSource_to_cName.get(l.leadsource)) != null) {
			CampaignMember cml = new CampaignMember();
			cml.leadid = l.id;
			cml.campaignid = map_cName_to_cID.get(map_lSource_to_cName.get(l.leadsource));
			theCampaignMembers.add(cml);
		}

	}

	/*
	* Insert the list of Campaign Members
	*/
	if(!theCampaignMembers.isEmpty()){
		insert theCampaignMembers;
	}

}

Updated Test Class (100% code coverage)
I updated the test class too to make it cover 100% of the code.

public class Create_CampaignMember_For_New_Leads {

	static testMethod void Create_CampaignMember_For_New_Leads() {

		// Create a Campaign to be matched on
		Campaign C1 = new Campaign();
		C1.Name = 'Matching Campaign';
		insert C1;

		// Create a Lead with a Lead Source matching a Campaign
		Lead L1 = new Lead();
		L1.lastname = 'Create_CampaignMember_For_New_Leads';
		L1.firstname = 'Test For';
		L1.company = 'Company ABC';
		L1.leadsource = 'Matching Campaign';

		insert L1;
		String holder = L1.id;

		List <CampaignMember> cm = [select id from CampaignMember where leadid = :holder limit 1];
		system.AssertEquals(1,cm.size());

		// Create a Lead without a Lead Source matching a Campaign
		Lead L2 = new Lead();
		L2.lastname = 'Create_CampaignMember_For_New_Leads';
		L2.firstname = 'Test For';
		L2.company = 'Company ABC';
		L2.leadsource = 'No Matching Campaign';

		insert L2;

		String holder2 = L2.id;

		List <CampaignMember> cm2 = [select id from CampaignMember where leadid = :holder2 limit 1];
		system.AssertEquals(0,cm2.size());

	}

}

Feel free to make additional recommendations on this code. I updated the Arrowpointe Google Code Site with this code too.

Leave a Comment

All comments are moderated. Other visitors will not see your comment until it has been approved.