Triggers – Helping to catch duplicates.
One way in which triggers can be of great help is by using them to catch duplicates records before insertion or before doing an update. Probably the easiest way to do this is by making sure you have implemented a unique key identifier on those records that you want to control and make sure that will not contain any duplicates.
The unique identifier needs to be, well… ‘unique’, and no other record should contain that same key.
Depending on the object in which you want to implement your “duplication preventer” you need to come up with that field that will contain your unique identifier.
Let’s take the Lead object for our test here, and I am going to use two unique values fields. Normally you should be able to use something like the Email Address field, but we are going to use the Phone and Mobile Phone for this example.
The business requirements for this are the following:
1. We need to stop data contamination on new Leads coming to our SFDC org.
2. Phone and Mobile Phone should be the identifiers
3. If any of those values are in the system assigned to an existing Lead, an error should be displayed to the user
on the field causing the alert.
4. Saving of the new record shouldn’t be allowed
It is clear what we want to accomplish here, let’s take a look at the code.
This code will check for Phone and MobilePhone numbers on any Lead before you try to insert or update a record. If it finds that any of those two fields are equal to a Lead record already in the system it will fire an error on the field that is causing the possible duplication.
/********************************************************************************
*
* Trigger on Leads to catch duplicates based on Phone and Mobile Phone
*
********************************************************************************/
trigger leadPhoneAndMobilePhoneDup on Lead (before insert, before update){
//We created a Map to insert or Leads
Map<String, Lead> leadMap =new Map<String, Lead>();
for (Lead lead : System.Trigger.new)
{
//We want to target those new leads with a Phone and compare them with the phones
//of leads that are already in our database.
if ((lead.Phone !=null) &&
(System.Trigger.isInsert ||
(lead.Phone != System.Trigger.oldMap.get(lead.Id).Phone)))
{
//Firing error if we find a lead that already has the same Phone
if (leadMap.containsKey(lead.Phone))
{
lead.Phone.addError(‘Another new lead has the same Phone address.’);
//If not found, we add the lead to our leadMap
}else{
leadMap.put(lead.Phone, lead);
}
}
//Same operation but targeting the MobilePhone
if ((lead.MobilePhone !=null) &&
(System.Trigger.isInsert ||
(lead.MobilePhone != System.Trigger.oldMap.get(lead.Id).MobilePhone)))
{
if (leadMap.containsKey(lead.MobilePhone))
{
lead.MobilePhone.addError(‘Another new lead has the same Phone address.’);
//If not found, we add the lead to our leadMap
}else{
leadMap.put(lead.MobilePhone, lead);
}
}
}
//We query our Leads and use the Phone as the reference. If found on our map, throw an error
for (Lead lead: [SELECT Phone FROM Lead
WHERE Phone IN :leadMap.KeySet()])
{
Lead newLead = leadMap.get(lead.Phone);
//Error needs to be on the field that is causing it, in this case, the Phone field
newLead.Phone.addError(‘A lead with this Phone address already exists.’);
}
//We query our Leads and use the Mobile Phone as the reference. If found on our map, throw an error
for (Lead lead: [SELECT MobilePhone FROM Lead
WHERE MobilePhone IN :leadMap.KeySet()])
{
Lead newLead = leadMap.get(lead.MobilePhone);
//Error needs to be on the field that is causing it, in this case, the Mobile Phone field
newLead.MobilePhone.addError(‘A lead with this Mobile Phone address already exists.’);
}
}
Some interesting points here are the oldMap and how it will help us to create a key using the fields in our page layout.
It is important to remember that oldMap: Is a map of IDs to the old versions of the sObject records.
This map is only available in “update” and “delete” triggers.
You can better get all this logic in a helper class and just use the trigger to invoke that class and execute the logic.
[…] Didn’t tested but something like this should work… You can see a similar approach in my bloq: […]