[SalesForce] Apex Trigger – Update Lead If Contact with Same Email Already Exists

I have a trigger implemented that will change the lead status to converted if a contact is created with the same email address. I'm trying to create a new trigger that changes a lead status to converted if the lead is inserted and a contact already exists with the same email address as that lead. I believe the following to be correct, except for this section:

for(Lead singleLead:leads){
    singleLead.Status = 'Converted';
}

I get this – Error: Compile Error: Loop variable must be of type SOBJECT:Contact at line 16 column 14. After trying almost literally every combination of lead and contact objects there I can't figure out how to make this work. I can eliminate one error message, only to create another until I'm right back where I started.

Here is the full code:

trigger ConvertLead on Lead (after insert) {
    List<String> leadEmails = new List<String>();
    for(Lead lead:Trigger.new){
        leadEmails.add(lead.Email);
    }

    List<Contact> leads = [
        SELECT 
            Id, Email 
        FROM 
            Contact
        WHERE 
            Email IN :leadEmails
    ];

    for(Lead singleLead:leads){
        singleLead.Status = 'Converted';
    }

    update leads;
}

Thank you for your help!

Best Answer

Your problem is in this piece of code:

List<Contact> leads = [
    SELECT 
        Id, Email 
    FROM 
        Contact
    WHERE 
        Email IN :leadEmails
];

for(Lead singleLead:leads){
    singleLead.Status = 'Converted';
}

Notice how yourleads variable is a List<Contact>. You then try to loop over that list and cast each item in the List as a Lead. You can not do this. Those items are Contacts.

Try something like this out instead:

trigger ConvertLead on Lead (before insert) {
    List<String> leadEmails = new List<String>();
    for(Lead lead:Trigger.new){
        leadEmails.add(lead.Email);
    }

    List<Contact> contacts = [
        SELECT 
            Id, Email 
        FROM 
            Contact
        WHERE 
            Email IN :leadEmails
    ];

    Set<String> contactEmails = new Set<String>();
    for(Contact contact:contacts){
        contactEmails.add(contact.Email);
    }

    for(Lead lead:Trigger.new){
        if(contactEmails.contains(lead.Email){
            lead.Status = 'Converted';
        }
    }
}

First off, notice I changed the trigger to a before insert. The reason for this is because you will receive an error if you attempt to perform a DML operation on the object a trigger is run on in an after context. The reason this is not allowed is because it would put the code in an infinite loop.

Secondly, notice that I changed your variable names to be more descriptive. I renamed your Contact list variable to contacts. This is a core concept of Clean Code.

Thirdly, I used a Set to store all matching Contact emails in the database. This will only keep one value for each of the unique email addresses found by the SOQL query.

Finally, you will notice I removed all DML operations. With the trigger changing to before insert, there is no need to run a DML operation as the object will be inserted directly after the trigger runs.


NOTE: This is not production ready code. I have not attempted to run it and wrote it specifically on this site. You must write unit tests for it and do your own testing to verify it does what you intend. Good luck!

Related Topic