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
WikWik 

Issue with the Trigger

Hi,

the following trigger was designed to prevent duplicate contacts on an account. But even when i edit the same contact and click save, the trigger acts and does not let me save the contact.

please help me figure out whats wrong with the trigger

trigger PreventDuplicateContact on Contact (after insert,after update) {
   
    if(trigger.isInsert || trigger.isUpdate)
    {
        Map<Id,List<Contact>> accMap = new Map<Id,List<Contact>>();
        List<Contact> contactList;
       
        for(Contact c: [Select Id,Email,accountId from Contact]){
            if(accMap.containsKey(c.accountId)){  
                accMap.get(c.accountId).add(c);
            }
            else{
                contactList = new List<Contact>();
                contactList.add(c);
                accMap.put(c.accountId,contactList);
            }      
        }
       
        for (Contact c : Trigger.new)
        {
            if(accMap.containsKey(c.accountId)){
                for(Contact con : accMap.get(c.accountId)){
                    if(c.Email == con.Email){
                       // c.Email.addError('Contact with this email address already exists.Please create a Contact Role. <a href=https://cs18.salesforce.com/02Z/e?parentId='+c.accountid+'\'>Create a Contact Role</a>',false);
                       String baseUrl = URL.getSalesforceBaseUrl().toExternalForm()+'/02Z/e?parentId=';
string errorMsg = '<a style=\'color:1B2BE8\'href="'+baseUrl+ c.accountid +'"> Create a Contact Role  </a>';

c.Email.addError('Contact with this email address already exists.Please create a Contact Role'+ errorMsg,false);
                    }
                }
            }
        }
    }
}

Best Answer chosen by Wik
Fabien TaillonFabien Taillon
It's because your are querying all the contacts, including the one your updating. So in fact your code finds a record with the same email, which in fact is himself !
So you should check that the 2 contacts with the same email don't have the same Id, to be sure it's different records.

Two other things :
  • You should filter your account list to only query the ones related to the contacts you are saving, otherwise you will query all the Contact table for nothing. This may probably hit a governor limit in the future
  • Instead of creating a map with a for loop, you can query the Account table and get the related Contact list like this : Select Id, (Select Id, Email From Contacts) From Account. Then you can loop through your accounts, and inside loop again on your related Contacts :
for (Account acc : [Select Id, (Select Id, Email From Contacts) From Account])
{
    for (Contact c : acc.Contacts)
    {
        // Do something with c.Id and c.email
    }
}

All Answers

Steve RobbinsSteve Robbins
If you want to edit existing records (update) then the trigger will always run.  You are mapping your contact on update, then, of course, finding it when looping throught the new values.    Perhaps you want an Insert trigger only.
WikWik

what is happening here is let's say i created a Contact. Now when i go and try and edit this contact to update some information, even then the trigger is acting and this does not let me save the update to contact.

this should not have happened actually.

Fabien TaillonFabien Taillon
It's because your are querying all the contacts, including the one your updating. So in fact your code finds a record with the same email, which in fact is himself !
So you should check that the 2 contacts with the same email don't have the same Id, to be sure it's different records.

Two other things :
  • You should filter your account list to only query the ones related to the contacts you are saving, otherwise you will query all the Contact table for nothing. This may probably hit a governor limit in the future
  • Instead of creating a map with a for loop, you can query the Account table and get the related Contact list like this : Select Id, (Select Id, Email From Contacts) From Account. Then you can loop through your accounts, and inside loop again on your related Contacts :
for (Account acc : [Select Id, (Select Id, Email From Contacts) From Account])
{
    for (Contact c : acc.Contacts)
    {
        // Do something with c.Id and c.email
    }
}
This was selected as the best answer
Steve RobbinsSteve Robbins
Exactly, when you edit a contact , you are Updating it's record.  You have an  (after insert,after update) trigger.  Of course it will run on update (edit) of a record.

Perhaps you should code an after Insert trigger to test new records only.