Saturday 23 November 2013

Apex: How to write a deduping trigger for leads and contacts.

This trigger will prevent creating a lead that already exists as a contact.


Code is not complicated its a case of breaking it down into smaller steps:

1 - Lead is created or updated
2 - Lead has an email address
3 - Try to find a matching Contact based on email address (using SOQL!)
4 - If a match is found, give the user an error
5 - If a match is not found, do nothing

<start------------->
trigger FindDupes on Lead (before insert, before update) {
  for (Lead myLead : Trigger.new) {
    if (myLead.Email != null) {
      List<contact> dupes = [SELECT Id FROM Contact
                               WHERE Email = :myLead.Email];
      if (dupes != null && dupes.size() > 0) {
        String errorMessage = 'Duplicate contact found! ';
        errorMessage += 'Record ID is ' + dupes[0].Id;
        myLead.addError(errorMessage);
      }
    }
  }
}
<end--------------->

I will begin with the outer lines of code and work inwards:

trigger FindDupes on Lead (before insert, before update) {
  ...
}

The only important decision we made here was to fire the trigger before a lead is inserted and before one is updated. Why not just before an insert? Because it’s possible that a Lead’s email address is updated to a duplicate value!


for (Lead myLead : Trigger.new) {
  ...
}

Trigger.new is the name of the List of records that were “triggered” in Salesforce. It’s a list because multiple records can go through a trigger at once if a mass update is done in Salesforce! We loop across all these records and give a name to the Lead in the current loop interation: “myLead”.

if (myLead.Email != null) {
  ...
}

Here wyou’re just checking if the current Lead has an email address. You’re using this field to dedupe with Contacts, and it’s possible that a lead is created/updated without it populated, so this step is not to be overlooked! Without this step, we’d probably get a null pointer exception somewhere down the line (the most common error in Salesforce!).

List<contact> dupes = [SELECT Id FROM Contact
                         WHERE Email = :myLead.Email];

This is a SOQL query that attempts to find a matching Contact by email using a bind variable. The query returns a list of all matching results because there can be multiple matches (or none)!

One very handy feature of SOQL is that you can use existing variables in a query. All you have to add a colon (:) before the variable as we do with myLead.Email.

if (dupes != null && dupes.size() > 0) {
  ...
}

Now you make sure the query has results. size() is a standard method of every List that you can call using dot notation – it simply returns the number of records inside. If there are none, you do nothing further with the Lead and move on to the next one.

String errorMessage = 'Duplicate contact found! ';
errorMessage += 'Record ID is ' + dupes[0].Id;
myLead.addError(errorMessage);

These are the final lines of code in our trigger! We’ll only reach this point if at least one duplicate Contact is found. We construct an error message in a String variable, then use the standard addError() method via dot notation to notify the user of the dupe. Using += lets us append more information to our errorMessage variable.

We do something interesting here with the error message. It’s customized so that the user will see the ID of the duplicate Contact record so that they navigate to it instead.

Although there can be multiple dupe matches, we keep things simple and show the first match using a bracket notation. [0] lets us select the first Contact in the “dupe” list. [1] would select the second – note that the index starts at 0!


THAT'S THE TRIGGER EXPLAINED.....HOWEVER EVERY TRIGGER NEEDS A CLASS


<start------------->
public class ContactDeduper {

    public static List<account> mergeDupeContactsInAnAccount(List<account> accList) {
 
        // Create a set of duplicate contacts that we will delete later. We use a set because it has the contains() method
        Set<contact> duplicates = new Set<contact>();
 
        // For each account, we will loop over every contact to find a dupe
        for (Account a : accList) {
     
            // There needs to be at least 2 contacts to have a dupe
            if (a.Contacts != null && a.Contacts.size() > 1) {
 
                // Iterate across the account's contacts to find dupes
                for (Contact outerContact : a.Contacts) {
             
                    // Skip this contact if it has been identified as a dupe
                    if (duplicates.contains(outerContact)) { continue; }
             
                    // Iterate again though the contacts to find a match by email or name
                    for (Contact innerContact : a.Contacts) {
                 
                        // Skip this contact if it has been identified as a dupe
                        if (duplicates.contains(innerContact )) { continue; }
                 
                        // Since the original contact is in this list, make sure we don't match it
                        if (outerContact.Id != innerContact.Id) {
                     
                            // Check for a match by email
                            if (outerContact.Email != null && outerContact.Email.equals(innerContact.Email)) {
                                duplicates.add(innerContact);
                                continue;
                            }
                         
                            // Now check for a match by name
                            if (outerContact.FirstName != null && innerContact.FirstName != null) {
                                String outerContactName = outerContact.FirstName + outerContact.LastName;
                                String innerContactName = innerContact.FirstName + innerContact.LastName;
                                if (outerContactName.equals(innerContactName)) {
                                    duplicates.add(innerContact);
                                    continue;
                                }
                            }
                         
                        }
                     
                    }
                 
                }
             
            }
         
        }
     
        // Delete dupes
        if (duplicates.size() > 0) {
            List<contact> duplicatesList = new List<contact>();
            duplicatesList.addAll(duplicates);
            delete duplicatesList;
        }
     
        return accList;
    }
}
<end--------------->

2 comments:

  1. Excellent Blog!!! Such an interesting blog with clear vision, this will definitely help many technologies to make them update.
    Salesforce Administrator 211 Training in Chennai
    Salesforce Developer 401 Training in Chennai

    ReplyDelete
  2. Wonderful blog on Cloud domain, Thank you sharing the informative article with us. Hope your article will reach top of the SERP result to the familiar cloud related queries
    Regards:
    cloud computing training in chennai
    cloud computing training

    ReplyDelete