AddThis Feed Button

Recent Items

Tags: Apex

My company sells software via the Internet. Wonderful business model, lots of happy customers all around the world. The software is priced so cheaply that we can’t afford to do in-person demonstrations nor respond to RFPs. Instead, we use WebEx to give online demonstrations.

The Sales and Marketing people would love to track the success of these Webinars, where “success” means that somebody bought something. So, I decided to use Campaigns to track Webinars, with the Campaign Member status indicating whether they had bought something. Though the clever use of a trigger, the status is updated when a purchase is made.

However, this still left the problem of loading the initial details about the Webinars and attendees (Contacts). Doing this manually would involve:

  • Creating a Campaign for each Webinar (or cloning an existing one) and filling in details (product, presenter, date)
  • Checking whether each attendee already had a Contact record in Salesforce.com (we don’t use Leads), and manually creating a Contact record for those not found
  • Linking each Contact to the Campaign, either via Manage Members on the Campaign (very slow), or by clicking Add Campaign on each Contact record (a bit easier)
  • Setting the Campaign Member status to ‘Attended’

We can’t use any Import functionality, since it is designed to import Leads (which we don’t use) or to update the status of members (not all of whom are necessarily Contacts yet).

For all this work, Sales would have the luxury of tracking how many people attended each webinar, and how many of them later purchased. But were they happy? No! They wanted it all done automagically.

So, I examined the format of a WebEx attendance export list and created a custom object to match. Users import the list via the Import Custom Object wizard, which then fires a trigger. The trigger then:

  • Creates a Campaign record (if required)
  • Creates Contact records (where required)
  • Adds a Campaign Member record (which links Campaigns to Contacts)

This was a day-long effort, only to be foiled at the last moment by DML governor limits. These limits are put in place by Salesforce.com to protect their multi-tenant architecture from being slowed down by individual users. Specifically, Triggers are only allowed 20 DML calls (insert, update, upsert, merge, or delete). There are various Bulk-Safe methods to avoid these limits but my Trigger was just too complex for such trickery.

Apex script unhandled trigger exception by user/organization
WebEx_Attendee: execution of BeforeInsert
caused by: System.Exception: Too many DML statements: 21
Trigger.WebEx_Attendee: line 128, column 9

So, I had to revert to using a static method off a class, which I hadn’t tried before. Somewhat more fiddly, since Force.com does a nice job of providing incoming records within Triggers, but it was fairly easy to convert the code from being a Trigger to being a Method.

Finally, there was the problem of how to activate the code. Triggers are easy, since they work when data is loaded. This situation, however, had to be user-controlled. So, I added a Button on the Campaign Page Layout which called my Apex code via the executeAnonymous function.

It doesn’t give a very user-friendly notice, but it does work! Please let me know if you have any recommendations of better ways to activate the code.

Update 2008-07-23: Even less DML

Well, I thought everything was good, but when I tested my code against real data (still in the sandbox, but using more data than just the TestMethod), I starting hitting even more Governor Limits.

The problem was, I had a major loop that did the following for each record:

  • Inserted a Campaign (if it didn’t already exist)
  • Inserted a Contact (if it didn’t already exist)
  • Inserted a CampaignMember

I had to ‘insert’ each time, otherwise my next iteration through the loop wouldn’t ‘see’ the recently added records. For example, if the same person attended two webinars, the first imported line would cause them to be created, but the second imported line had to detect the earlier insert so as not to insert the Contact again. (Confused yet?)

So, I totally rewrote the code to perform three loops — one each for campaigns, contacts and customers. As a result, I’ve gone from potentially 6 DML calls per record to 6 DML calls in total! It takes A bit of different thinking, but the results are wonderful — especially where one click and a couple of seconds suddenly produces hundreds of beautifully-linked records.

The Bottom Line

  • The Force.com platform is amazingly expandable
  • Apex gives ultimate flexibility since you can write anything
  • I really, really enjoy hacking!

2 Responses to “Creating Campaign Records for WebEx attendees”

  1. » Calling Apex from a Button - Beware! (The Enforcer.net, a force.com blog) Says:

    [...] Creating Campaign Records for WebEx attendees [...]

  2. » Loading Contacts into Campaigns (The Enforcer.net, a force.com blog) Says:

    [...] Creating Campaign Records for WebEx attendees [...]