feed-icon-32x32.png

Subscribe in Feed Reader
Subscribe by Email

Learn how Salesforce.com can help your business
arrowpointe @ twitter
  • anyone use Salesforce's knowledge base? (the old school one) Notice scrollbars appearing in the content recently? 17 hrs ago
  • yes, i can use aggregate functions in dynamic soql. asked too soon, sorry 23 hrs ago
  • can i use aggregate functions in the Database.query() method? 1 day ago
  • what's the timing for new IDE? will it run just as well on eclipse 3.4 as 3.5? major benefits of 3.5 (i only use eclipse for salesforce)? 1 day ago
  • anyone use campaignmonitor with salesforce? no integration, but seems like a slick tool. curious about your process re: subscriber sync 1 day ago
  • is there a apex method or query that can tell me whether a subscriber org has a Trial vs. Active license of my package they installed? 2 days ago
  • feels like the new salesforce ui uses JavaScript libraries and rendering more friendly to fitefox's memory issues. Real or my imagination? 3 days 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.

5 Comments »

  1. Steve Judd Said,

    August 24, 2009 @ 7:53 pm

    Scott,

    Thanks for your Apex Code for Creating Campaign members from the lead source. I’ve modified the code to allow multiple campaigns (up to 5) to be added from one web-to-lead form. Are you interested in posting the code on your site?

    Steve

  2. newbee Said,

    September 16, 2009 @ 9:17 am

    Hi,
    I’m a newbie on Apex code and I really need some help to make an update after insert/update.
    I’m trying to do something similar. I’d love to see your complete code.

    Thanks,
    newbee

  3. Scott Hemmeter Said,

    September 16, 2009 @ 9:43 am

    @newbee,

    The complete code is in the post.

  4. Marco Said,

    September 25, 2009 @ 5:02 am

    I think your test method are not bulk yet as you only insert a lead at a time. You should create and insert a list of Lead.

  5. Scott Hemmeter Said,

    September 25, 2009 @ 8:06 am

    @marco, good point. You are right.

RSS feed for comments on this post · TrackBack URI

Leave a Comment

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