Preventing Duplicate Records Based on Multiple Fields in Salesforce

Preventing duplicate records in Salesforce based on a single field can be achieved using a Set that can store the values of that specific field from all existing records and compare it with the list of new records that are going to be inserted.

Salesforce Duplicate Management can be achieved using a Set that can store the values of that specific field from all existing records and compare it with the list of new records that are going to be inserted.

The same approach won’t work if we need to prevent duplicate records based multiple fields, even if we use multiple sets. To solve the issue in Salesforce, one of the solutions is to create a Wrapper class with the hashcode and equals method in the class. The hashcode method creates a unique id for the individual wrapper class instance. This unique id is in turn used by Salesforce to ensure uniqueness of the records.

Example: Let us look at two scenarios—one for single field and another one for multiple fields.

The user should not be able to create a new lead with the same LASTNAME and EMAIL.

SCENARIO 1:

Let us consider the method used for single field using the SET.

Create a new trigger in lead object and past the below code.

trigger AvoidDuplicate on Lead (before insert)

{    

    set<string> newNameSet = new set<string>();newNameSet = new set<string>();

    set<string> newEmailSet = new set<string>();

    set<string> dbNameSet = new set<string>();

    set<string> dbEmailSet = new set<string>();

    for(lead newLead : trigger.new){

        newNameSet.add(newLead.LastName);

        newEmailSet.add(newLead.Email);

    }

    for(Lead dbLead : [select id, LastName, email from lead where email IN: newEmailSet OR LastName IN: newNameSet]){newNameSet]){

        dbNameSet.add(dbLead.LastName);

        dbEmailSet.add(dbLead.Email);

    }

    for(lead newLead : trigger.new){

        if(dbNameSet.contains(newLead.LastName) && dbEmailSet.Contains(newLead.Email))

            newLead.addError('You are inserting Duplicate lead');

    }

}

Assume that the database has 5 Lead records as follows:

LastNameEmailCompany
Test Name 1testuser1@gmail.comTest Company
Test Name 2testuser2@gmail.comTest Company
Test Name 1testuser3@gmail.comTest Company
Test Name 3testuser2@gmail.comTest Company
Test Name 3testuser3@gmail.comTest Company

The records that we are going to insert:

LastNameEmailCompanyDuplicate Result
Test Name 1testuser4@gmail.comTest CompanyNot Duplicate
Test Name 3testuser3@gmail.comTest CompanyDuplicate.
Test Name 2testuser2@gmail.comTest CompanyDuplicate.

From the above set of records only one record should be inserted and remaining two records must show an ERROR message.

Now as shown in the trigger, we have two different sets holding the values of Email and Last Name, respectively

dbEmailSet

testuser4@gmail.com
testuser3@gmail.com
testuser2@gmail.com
testuser1@gmail.com

dbNameSet

Test Name 1
Test Name 3
Test Name 2

Now we process the first lead record.

(i.e.) LastName : Test Name 1 , Email : testuser4@gmail.com , Company : Test Company.

for(lead newLead : trigger.new){

       if(dbNameSet.contains(newLead.LastName) && dbEmailSet.Contains(newLead.Email))

           newLead.addError('You are inserting a duplicate lead');

}

The above code will throw an error message for the above record based the Last Name Test Name 1 that already exists in the dbNameSet Set as well as the email TESTUSER4@GMAIL.COM exists in the dbEmailSet Set; however, the record we are trying to insert is not a duplicate record based on the combination of Last Name and Email

SCENARIO 2:

Here, the issue with the Scenario 1 is addressed using a different approach—using a Wrapper class.

Create a new class and paste the below code.

public class WrapperClassWrapperClass

{

    public string lastName;

    public string email;

    public WrapperClass(string leadName , string leadEmail){WrapperClass(string leadName , string leadEmail){

        lastName = leadName;

        email = leadEmail;

    }

    public Boolean equals(Object obj) {

        if (obj instanceof WrapperClass) {WrapperClass) {

            WrapperClassWrapperClass p = (WrapperClass)obj;WrapperClass)obj;

            return ((lastName==p.lastName) && (email==p.email));

        }

        return false;

    }

    public Integer hashCode() {

        return (2 * lastName.hashCode()) ^ email.hashCode();

    }

}

Here, the hashcode method provides a unique ID for the combination of two variables. (i.e.) Lead’s LastName and Email.  The equals method returns a boolean value. If the combination of two different fields values are repeated, then the equals method return true; otherwise, it returns the value as false.

Now, modify the lead trigger and past the below code.

trigger AvoidDuplicate on Lead (before insert)

{    

    set<string> newNameSet = new set<string>();newNameSet = new set<string>();

    set<string> newEmailSet = new set<string>();

    set<WrapperClass> dbWrapperSet = new set<WrapperClass>();WrapperClass> dbWrapperSet = new set<WrapperClass>();

    set<WrapperClass> newWrapperSet = new set<WrapperClass>();WrapperClass> newWrapperSet = new set<WrapperClass>();

    for(lead newLead : trigger.new){

        WrapperClassWrapperClass iKey = new WrapperClass(newLead.LastName , newLead.Email);WrapperClass(newLead.LastName , newLead.Email);

        if(newWrapperSet.contains(iKey)){

            newLead.addError('Duplicate in new list');

        } else {

            newNameSet.add(newLead.LastName);

            newEmailSet.add(newLead.Email);

            newWrapperSet.add(iKey);

        }

    }

    for(Lead dbLead : [select id, LastName, email from lead where email IN: newEmailSet OR LastName IN: newNameSet]){newNameSet]){

        dbWrapperSet.add(new WrapperClass(dbLead.LastName , dbLead.Email));WrapperClass(dbLead.LastName , dbLead.Email));

    }

    for(lead newLead : trigger.new){

        WrapperClassWrapperClass iKey = new WrapperClass(newLead.LastName , newLead.Email);WrapperClass(newLead.LastName , newLead.Email);

        if(dbWrapperSet.contains(iKey))

            newLead.addError('You are inserting Duplicate lead');

    }

}

Now, let us assume that the database has five records as follows:

LastNameEmailCompany
Test Name 1testuser1@gmail.comTest Company
Test Name 2testuser2@gmail.comTest Company
Test Name 1testuser3@gmail.comTest Company
Test Name 3testuser2@gmail.comTest Company
Test Name 3testuser3@gmail.comTest Company

The records that we are going to insert:

LastNameEmailCompanyDuplicate Result
Test Name 1testuser4@gmail.comTest CompanyNot Duplicate
Test Name 3testuser3@gmail.comTest CompanyDuplicate.
Test Name 1testuser4@gmail.comTest CompanyDuplicate in new list

From the above set of records, only one record should be inserted and the remaining two records must show a different error message– one saying that duplicate in new list and other one must show record already exists in database.

Now, let us look at the values (example) dbWrapper Set will be holding.

dbWrapperSet

Wrapper ValueUnique ID
WrapperClassWrapperClass: [lastName = Test Name 1, email = testuser1@gmail.com]12123
WrapperClassWrapperClass: [lastName = Test Name 2, email = testuser2@gmail.com]21234
WrapperClassWrapperClass: [lastName = Test Name 1, email = testuser3@gmail.com]21241
WrapperClassWrapperClass: [lastName = Test Name 3, email = testuser2@gmail.com]54324
WrapperClassWrapperClass: [lastName = Test Name 3, email = testuser3@gmail.com]32432

Each set value/wrapper class will have its unique id that will not be repeated. The users will not be able to see the values.

Now, let us process the first lead record.

(i.e.) LastName : Test Name 1 , Email : testuser4@gmail.com , Company : Test Company.

for(lead newLead : trigger.new){

        WrapperClassWrapperClass iKey = new WrapperClass(newLead.LastName , newLead.Email);WrapperClass(newLead.LastName , newLead.Email);

        if(dbWrapperSet.contains(iKey))

            newLead.addError('You are inserting a Duplicate lead');

    }

The wrapper class values for this record would be: WrapperClass: [lastName = Test Name 1, email = WrapperClass: [lastName = Test Name 1, email = testuser4@gmail.com]; so, in the background, the Unique ID will be generated for this wrapper class (i.e.) 98980. We can see that this unique ID doesn’t match with any of the existing values; so, it will not show any error and the record will be inserted successfully.

Now, we will process the second lead record.

(i.e.) LastName : Test Name 3 , Email : testuser3@gmail.com , Company : Test Company.

for(lead newLead : trigger.new){

        WrapperClassWrapperClass iKey = new WrapperClass(newLead.LastName , newLead.Email);WrapperClass(newLead.LastName , newLead.Email);

        if(dbWrapperSet.contains(iKey))

            newLead.addError('You are inserting a Duplicate lead');

    }

The unique ID of this record is 32432 that already exists in the dbWrappetSet. So, it will show the error message: “You are inserting a duplicate Lead”.

After these two records are processed, the newWrapperSet will hold the values, like these:

newWrapperSet

Wrapper ValueUnique ID
WrapperClassWrapperClass: [lastName = Test Name 1, email = testuser4@gmail.com]98980
WrapperClassWrapperClass: [lastName = Test Name 3, email = testuser3@gmail.com]32432

Now for the third record, the unique ID will be 98980 and it already exists in the newWrapperSet; so, it will show an error message as Duplicate in new list; meaning, there are some duplicate records in the list of the new records to be inserted.

So the best way to identify the duplicate records based on multiple fields in Salesforce is to use the wrapper class with the hashcode method.

Reference: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/langCon_apex_collections_maps_keys_userdefined.htm

About MST

At MST Solutions our cornerstone is to adapt, engage and create solutions which guarantee the success of our clients. The talent of our team and experiences in varied business verticals gives us an advantage over other competitors.

Recent Articles

Work with us.

Our people aren’t just employees, they are key to the success of our business. We recognize the strengths of each individual and allow them time and resources to further develop those skills, crafting a culture of leaders who are passionate about where they are going within our organization.