You are using an older browser that might negatively affect how this site is displayed. Please update to a modern browser to have a better experience. Sorry for the inconvenience!

Preventing Duplicate Records Based on Multiple Fields in Salesforce


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:

LastName

Email

Company

Test Name 1

testuser1@gmail.com

Test Company

Test Name 2

testuser2@gmail.com

Test Company

Test Name 1

testuser3@gmail.com

Test Company

Test Name 3

testuser2@gmail.com

Test Company

Test Name 3

testuser3@gmail.com

Test Company

The records that we are going to insert:

LastName

Email

Company

Duplicate Result

Test Name 1

testuser4@gmail.com

Test Company

Not Duplicate

Test Name 3

testuser3@gmail.com

Test Company

Duplicate.

Test Name 2

testuser2@gmail.com

Test Company

Duplicate.

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

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:

LastName

Email

Company

Test Name 1

testuser1@gmail.com

Test Company

Test Name 2

testuser2@gmail.com

Test Company

Test Name 1

testuser3@gmail.com

Test Company

Test Name 3

testuser2@gmail.com

Test Company

Test Name 3

testuser3@gmail.com

Test Company

The records that we are going to insert:

LastName

Email

Company

Duplicate Result

Test Name 1

testuser4@gmail.com

Test Company

Not Duplicate

Test Name 3

testuser3@gmail.com

Test Company

Duplicate.

Test Name 1

testuser4@gmail.com

Test Company

Duplicate 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 Value

Unique 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 Value

Unique 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