function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
si risi ri 

Restrict creation of duplicate contacts for an Account

I have a requirement that for an account there should be unique email id for every related contact. But in my code it is not working as per the requirement, it is checking all the contacts irrespective of Account. 
But I need to check only Account related contacts email id's.Here is my code please help me where I am doing wrong.

trigger ContactTrigger on Contact (before insert,before update)
 {
   
  set<ID> accId = new set<ID>();
   list<string> ContactEmails=new list<string>();
    for(Contact conVar:trigger.new)
    {
        ContactEmails.add(conVar.email);
        accId.add(conVar.AccountId);
    }
    
    system.debug('ContactEmails ************' +ContactEmails);
    
    list<Contact> listOfDuplicateContacts=[select id,email,Account.ID from Contact where email in :ContactEmails AND AccountID IN : accId];
      system.debug('listOfDuplicateContacts ************' +listOfDuplicateContacts);
    
    for(Contact con:trigger.new)
    {
        if(trigger.isInsert){
        if(listOfDuplicateContacts.size()!=0)
        {
            con.addError('Contact email already exists with this name');
        }
        }
        if(trigger.isUpdate)
        {
           for(Contact oldContact :trigger.old)
           {
               if(con.Email!=oldContact.Email && listOfDuplicateContacts.size()!=0)
               {
                   con.addError('Contact email already exists with this name');
               }
           }
        }
    }
}
Best Answer chosen by si ri
Dushyant SonwarDushyant Sonwar


I did some refactoration of your code . Please try this , it should work fine
trigger ContactTrigger on Contact (before insert,before update){
   
	set<ID> accountIds = new set<ID>();
	Map <String , Contact> mapToCheckDuplicateContacts = new Map <String , Contact>();
	set<String> setCheckDuplicateinSameList = new set<String>(); //check Duplicates in the Same List Bulk Insertion
    for(Contact conVar:trigger.new){
		
		if(setCheckDuplicateinSameList.contains(conVar.Email +'-'+ conVar.AccountId)){
			conVar.addError('Duplicae Contact in Bulk Insertion');
		}
		
		if(!setCheckDuplicateinSameList.contains(conVar.Email +'-'+ conVar.AccountId)){
			setCheckDuplicateinSameList.add(conVar.Email +'-'+ conVar.AccountId);
		}
		if(trigger.isInsert){
			if(conVar.Email != null){
				accountIds.add(conVar.accountId);
			}
		}
		if(trigger.isUpdate){
			if(trigger.oldMap.get(conVar.Id).AccountId != conVar.AccountId 
				|| trigger.oldMap.get(conVar.Id).Email != conVar.Email){
				if(conVar.Email != null){
					accountIds.add(conVar.accountId);					
				}
				
			}
		}
		
    }
    
   if(accountIds.size() > 0){ 
		for(Contact conObj :[Select id,email , accountId from contact where accountId in:accountIds]){
			mapToCheckDuplicateContacts.put(conObj.Email +'-'+ conObj.AccountId , conObj);
		}
		
		for(Contact con:trigger.new){
			if(mapToCheckDuplicateContacts.containsKey(con.Email +'-'+ con.AccountId) ){
				con.addError('Contact Exists');
			}
		}
	}
}

 

All Answers

MKRMKR
Hi,

You should check the relationships between account and email. Currently you are just querying all matching email addresses from the accounts and not checking to which account does the email belong to. Try this:
 
trigger ContactTrigger on Contact (before insert,before update) {
     Set<Id> accId = new Set<Id>();
     Set<Id> contactIDs = new Set<Id>();
     List<String> contactEmails = new List<String>();
     for(Contact conVar : Trigger.New) {
          contactEmails.add(conVar.Email);
          accId.add(conVar.AccountId);

          //Do not query the same records which are currently being updated
          if(Trigger.isUpdate) {
               contactIDs.add(conVar.Id);
          }
    }
    
    List<Contact> listOfDuplicateContacts=[select id,email,AccountID from Contact where email in :ContactEmails AND AccountID IN : accId AND Id NOT IN :contactIDs];
    
    //Create map to hold relationships between accounts and existing email addresses
    Map<Id, Set<String>> accountToEmailsMap = new Map<Id, Set<String>>();
    for(Contact existingContact : listOfDuplicateContacts) {
         if(!accountToEmailsMap.containsKey(existingContact.AccountId) {
              accountToEmailsMap.put(existingContact.AccountId, new Set<String>());
         }
         accountToEmailsMap.get(existingContact.AccountId).add(existingContact.Email);
    }

    for(Contact con:trigger.new) {
         if(accountToEmailsMap.containsKey(con.AccountId) {
              if(accountToEmailsMap.get(con.AccountId).contains(con.Email) {
                   con.addError('Contact email already exists with this name');
              }
         }
    }
}

Regards,
MKR
Dushyant SonwarDushyant Sonwar


I did some refactoration of your code . Please try this , it should work fine
trigger ContactTrigger on Contact (before insert,before update){
   
	set<ID> accountIds = new set<ID>();
	Map <String , Contact> mapToCheckDuplicateContacts = new Map <String , Contact>();
	set<String> setCheckDuplicateinSameList = new set<String>(); //check Duplicates in the Same List Bulk Insertion
    for(Contact conVar:trigger.new){
		
		if(setCheckDuplicateinSameList.contains(conVar.Email +'-'+ conVar.AccountId)){
			conVar.addError('Duplicae Contact in Bulk Insertion');
		}
		
		if(!setCheckDuplicateinSameList.contains(conVar.Email +'-'+ conVar.AccountId)){
			setCheckDuplicateinSameList.add(conVar.Email +'-'+ conVar.AccountId);
		}
		if(trigger.isInsert){
			if(conVar.Email != null){
				accountIds.add(conVar.accountId);
			}
		}
		if(trigger.isUpdate){
			if(trigger.oldMap.get(conVar.Id).AccountId != conVar.AccountId 
				|| trigger.oldMap.get(conVar.Id).Email != conVar.Email){
				if(conVar.Email != null){
					accountIds.add(conVar.accountId);					
				}
				
			}
		}
		
    }
    
   if(accountIds.size() > 0){ 
		for(Contact conObj :[Select id,email , accountId from contact where accountId in:accountIds]){
			mapToCheckDuplicateContacts.put(conObj.Email +'-'+ conObj.AccountId , conObj);
		}
		
		for(Contact con:trigger.new){
			if(mapToCheckDuplicateContacts.containsKey(con.Email +'-'+ con.AccountId) ){
				con.addError('Contact Exists');
			}
		}
	}
}

 
This was selected as the best answer
si risi ri
Thanks Dushyant Sonwar. I will check and revert.
si risi ri
Hi Dushyant Sonwar,
Thank you very much. Could you please elaborate me the logic in this trigger in detail,as I am new to apex coding.
Dushyant SonwarDushyant Sonwar
First we created a map of  unique key which are in database  of account and email ,  so that if it matches then throw error .
In Update case , we are only runnig the logic if contact and email is changed.
Also checking the setCheckDuplicateinSameList  same list , if some one tries to insert csv with duplicate email .



 
si risi ri
Thanks Dushyant for the elaboration. If anything further required, I will let you know.