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
RockerRocker 

Error on After Update Trigger on Contact

Hello,

 

I am new to Apex and I wrote this trigger to update all duplicate contacts when the "Email Opt Out" field is updated. The code has 100% test coverage and I tested it in the sandbox with single records and a bulk update of 1,000 contacts. The trigger worked fine in both cases but now that it is deployed to production and Cast Iron tried to update some records, it failed with the error below.

 

Any ideas on how to change the code so that it works? Maybe it is because I am not using an indexed field like ID?

 

I am getting this error:

 

updateContactOnEmailOptOutChange: execution of AfterUpdate  caused by: System.QueryException: Non-selective query against large object type (more than 100000 rows). Consider an indexed filter or contact salesforce.com about custom indexing. Even if a field is indexed a filter might still not be selective when: 1. The filter value includes null (for instance binding with a list that contains null) 2. Data skew exists whereby the number of matching rows is very large (for instance, filtering for a particular foreign key value that occurs many times)  Trigger.updateContactOnEmailOptOutChange: line 31, column 1

 

 

trigger updateContactOnEmailOptOutChange on Contact (after update) {

// On a contact update, this trigger updates all duplicate contacts with the new value of "Email Opt Out" if this field has been updated.
// Duplicate contacts are contacts with an identical email address. This trigger only updates duplicate contacts that have a HasOptedOutOfEmail value
// different from the one being updated. 
//                                                                      
// Author: Manuel Dangond                                                                
// Date: 10/18/12                                                                                          
     
    //Initialize lists and maps

    List<Contact> duplicateContacts = new List<Contact>();
    Map<String, Contact> contactEmailMap = new Map<String, Contact>();
    Map<Id, Contact> contactIdMap = new Map<Id, Contact>();

    //Build a map with contacts to update. Only select the ones that have a different "Email Opt Out" value from the contact being updated.

    for (Integer i = 0; i < Trigger.new.size(); i++) {
        if (Trigger.old[i].HasOptedOutOfEmail != Trigger.new[i].HasOptedOutOfEmail) {
            contactEmailMap.put(Trigger.old[i].email, Trigger.new[i]);
            contactIdMap.put(Trigger.old[i].id, Trigger.new[i]);        
        }
    }    
    
    //Only go through this process if "Email Opt Out" (HasOptedOutofEmail) was updated.
    
    If (contactIdMap.size()>0) {
    
        //Query the database and look for all contacts with a duplicate email address (same email as the contact currently being updated).

        for (Contact dupContact : [SELECT Id, Name, Email, HasOptedOutOfEmail
                                   FROM Contact
                                   WHERE Email IN : contactEmailMap.KeySet()
                                   AND Id NOT IN : contactIdMap.KeySet()]) {
            Contact contact = contactEmailMap.get(dupContact.Email);
            If (dupContact.HasOptedOutOfEmail <> contact.HasOptedOutOfEmail) { 
                dupContact.HasOptedOutOfEmail = contact.HasOptedOutOfEmail;   
                duplicateContacts.add(dupContact);
            }
        }    
    
        //If any duplicate contacts were found, update all duplicate contacts with the new HasOptedOutOfEmail value.

       If (duplicateContacts.size()>0) update duplicateContacts;
   }
}

 

SFAdmin5SFAdmin5

hey manuel.  so, just looking at the error message not even looking at your code, i've hit that error before.  in my experience, there's basically no way to code around that with a trigger.  in my experience you can write a perfectly good trigger, which I'm sure you did (esp considering you did a manual bulk test on it with 1000 records), but you're just hitting a limit that you can't get around with a trigger.

 

i've had this problem before and it sucks.  it's probably not a reflection on your code not working, but rather a limitation imposed by SFDC on your code that you can't do anything about.  the two times we've hit that limit, we had to scrap our trigger work (which was a LOT of work), and do batch apex.  

 

in my own experience, I would first encourage you to try the indexed field option, though that probably won't work.  the reality is, you're probably dealing with a limit you can't get around with a trigger.  

 

i'm hoping (for your sake) someone on here much more knowledgable than I can re-write your trigger to make it work for your prod org, but my comment here is that you need to abandon the trigger and handle this with batch or scheduled batch apex.

 

RockerRocker

Thanks so much Ross!

 

I believe you are correct and I will change this trigger to a batch apex.

 

Thanks again!

Manuel Dangond