I have created a trigger and am hopping for suggestions to clean up the trigger, making it more performant.

The reason for this trigger is: The companies' website has a PHP insert, creating Contacts in Salesforce. However, it is possible that the contact already exists in Salesforce. (The current PHP module does not allow for external ids). My solution is to throw a specific error if the Contact email already exists. The error will contain the existing Contact ID.

To throw this error I think a trigger is the best option, and this way a 'duplicate' Contact will not be created and I will be able to send the existing Contact's Id through the error.

The trigger is as follows:

    trigger trig_Contact_webToContact on Contact (before insert) 
    //Defining Variables    
    String errorMsg = 'The email already exists on another Contact ';
    List<String>newEmail = new List<String>();
    List<Id>newID = new List<String>();

    List<Contact> newContacts = [SELECT id, email FROM Contact WHERE ID IN: Trigger.new];

    for(Contact newContact:newContacts) //put emails and Ids in a list for use in SELECT   

    //List of Contacts that have the same email as inserted
    List<Contact> existingContacts = [SELECT id, email FROM Contact WHERE email IN: newEmail AND id NOT IN: newID]; 

    if(existingContacts.size() > 0)
        for(Contact ContactError:existingContacts)
            for(Contact insertedContacts:newContacts)
                if(ContactError.Email == insertedContacts.Email)
                    errorMsg += ContactError.Id;

This trigger seems like it should work perfectly, but I feel I am repeating a few unnecessary steps. Any help on cleaning it up would be greatly appreciated.

3 Answers 3


I believe this should do the job (not tested it, though):

trigger trig_Contact_webToContact on Contact (before insert) 
  final String errMsg = 'The email already exists on another Contact: ';
  Set< String > emailSet = new Set< String >();
  for( Contact c : Trigger.new ) emailSet.add( c.Email );

  Map< String, Id > duplicateContactMap = new Map< String, Id >();

  for( Contact c : [select Id, Email from Contact where Email = :emailSet] )
    duplicateContactMap.put( c.Email, c.Id );

  for( Contact c : Trigger.new ){
    Id duplicateContactId = duplicateContactMap.get( c.Email );
    if( duplicateContactId != null )
      c.addError( errMsg + duplicateContactId );

Just to offer an alternative: you don't need code for this. "Less is more"; less apex code to maintain, less unit tests to write, faster deployments, cleaner debug logs, less query rows wasted, faster execution...

  1. Make a new field on Contact (type: Email, Unique: selected, External Id: if you feel like it). I'd go with "unique case insensitive" but it's your call.
  2. Make a new workflow rule
    • running: every time it's changed or edited
    • condition: ISNEW() || ISCHANGED(Email)
    • value: Email
    • remember to activate
  3. Run a data fix to populate it for all existing records. update [SELECT Id FROM Contact WHERE Email != null AND Unique_Email__c = null LIMIT 10000]; couple times should be ok.
  4. You're done.
  • Native first... nice approach here! And this will be reflected in anything and everything that talks to Contact. Jan 6, 2014 at 22:12
  • Thanks for the response eyescream, I agree with Less is more, however I don't think this will send my external "insert" call the contact ID if the contact already exists.
    – jnoel10
    Jan 7, 2014 at 13:14
  • It will throw a SOAP exception that will be translated to exception on PHP side. The message will be similar to System.DmlException: Insert failed. First exception on row 0; first error: DUPLICATE_VALUE, duplicate value found: Email__c duplicates value on record with id: 003xxxxxxxxxxxx: []
    – eyescream
    Jan 7, 2014 at 13:21
  • I agree that less is more on this case. Apex coding requires extra deploy cares, test classes, is subject to governor limits, consume Database time... This is the price Apex pays for being the most powerful and flexible tool in the box. Jan 7, 2014 at 15:54

I'm going to take a gamble here that you have access to the source of the PHP SOAP client.

Can you find this line:

$results = $client->insert($contacts)

and replace with:

$results = $client->upsert('Email', $contacts)

or look deeper into the SOAP implementation to do that?

  • Thanks for the quick reply. it's a Drupal module and there is a Push. The fix in the Push i was going to do is just change $mapped_objects = .... 'salesforce_id' => $result->id, to the returned error ID
    – jnoel10
    Jan 6, 2014 at 18:02
  • I do know if changing the upsert makes sense since it the function is used in more places than just Contacts, so email will not always be the upsert key.. however by looking for a specific error I can just send the Id received from the errorMsg
    – jnoel10
    Jan 6, 2014 at 18:05
  • System.debug(Contact.Email.getDescribe().isExternalId()); gives false so I wouldn't have too high hopes.
    – eyescream
    Jan 6, 2014 at 22:00

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .