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
andyKal10andyKal10 

Save error: Set of SOBJECT:Lead not allowed

The code below is my attempt at a lead dupe preventer. Rather than just prevent the insert of the lead I want to query the existing leads and contacts for records that have the same email and then update fields in those existing records. The class is receiving leads from an after update/insert trigger. The idea being to insert the lead then find if there are already any existing leads or contacts...update those records and then delete the lead that came from the trigger.

 

I tried to do this with one SOSL a little while ago, but have decided to go with 2 SOQL statements. Anyway, I am getting a strange save error when I try to save the code below: 'Save error: Set of SOBJECT:Lead not allowed'.  My first attempt at this was to make the variable "leadsToDelete" a List, but this attempt results in a duplicate id error in the delete statement in cases where the same lead is added to the list more than once, which is why I changed the varible to a Set but now I cant figure this error out.

 

Does anybody know of any reason for why I wouldn't be able to make a Set of Leads?

 

Thanks for any help.

 

 

 


public with sharing class leadHandler { Public Static Void leadDeDuper(Map<String,Lead> newLeads) { Set<Lead> leadsToDelete = new Set<Lead>(); List<Lead> existingLeads = new List<Lead>(); List<Contact> contactsToDelete = new List<Contact>(); List<Contact> existingContacts = new List<Contact>(); //finds existing Leads where their email equals the incoming Lead for(Lead leadB : [select Id, Name, Blog__c,Email,HasOptedOutofEmail,Product_Announcements__c, MarketingCampaign__c, Insights_Newsletter__c,Press_Releases__c from Lead where Email IN :newLeads.KeySet()]) { //adds the incoming lead to a set that will be deleted further down leadsToDelete.add(newLeads.get(leadB.email)); //updates fields in existing leads leadB.HasOptedOutOfEmail = false; leadB.Press_Releases__c = true; leadB.Insights_Newsletter__c = true; leadB.Product_Announcements__c = true; leadB.Blog__c =true; leadB.Marketing_Opt_Out__c = false; if(leadB.Insights_Newsletter__c == false || leadB.Press_Releases__c == false || leadB.HasOptedOutOfEmail == true){ existingLeads.add(leadB); } } if(existingLeads.size()>0) { update existingLeads; } //finds existing contacts where their email equals the incoming leads for(Contact contactA : [select ID, Name, Email, HasOptedOutofEmail, Insights_Newsletter__c, Press_Releases__c from Contact where Email IN :newLeads.keySet()]) { //adds the lead to a set to be deleted below leadsToDelete.add(newLeads.get(contactA.Email)); //updates the existing contact contactA.HasOptedOutOfEmail = false; contactA.Insights_Newsletter__c = True; contactA.Press_Releases__c = True; contactA.Product_Announcements__c = true; contactA.Blog__c = true; if(contactA.Insights_Newsletter__c == false || contactA.Press_Releases__c == false || contactA.HasOptedOutOfEmail == true) { existingContacts.add(contactA); } } if(existingContacts.size()>0) { update existingContacts; } if(leadsToDelete.size()>0) { delete leadsToDelete; } } }

 

 

 

gm_sfdc_powerdegm_sfdc_powerde

sets of sobjects are supported from summer 10 release.   Can you check the API version of your Apex class. If it's less than 19.0, consider migrating to 19.0 to get rid of this problem.

andyKal10andyKal10

That worked! Thanks a lot.  But now I get the following save error on the delete statement

 

Save error: DML requires SObject or SObject list type: Set<Lead>

 

I've  only just received it and haven't started looking for the fix yet, but thought I check with you for another quick answer.

 

Thanks,

Andy

jkucerajkucera

Looks like you can't update a Set - instead you'll have to use a List.

 

You can use your Set to validate uniqueness & then put only unique leads in a List which can be updated.

andyKal10andyKal10

Thanks John. I have given your advice a try. Before you posted I also enforced a unique Array by using Maps. However, in both attempts I now receive the error that "DML statement cannot operate on trigger.new or trigger.old". I found another post about this error and it said to use Database.delete rather than just the delete command.  This seemed to work for the lucky guy in the post but not for me. So, now I think I just need to go figure how to do this in a before insert trigger. I have posted my version that uses maps to enforce uniqueness so that you can see the two different delete statements I have tried at the bottom.

public with sharing class leadHandler {

    Public Static Void leadDeDuper(Map<String,Lead> newLeads) {
        Map<ID,Lead> leadsToDelete = new Map<ID,Lead>();
        List<Lead> existingLeads = new List<Lead>();
        List<Contact> contactsToDelete = new List<Contact>();
        List<Contact> existingContacts = new List<Contact>();
        
        //finds existing Leads where their email equals the incoming Lead
        for(Lead leadB : [select Id, Name, Blog__c,Email,HasOptedOutofEmail,Product_Announcements__c, MarketingCampaign__c, Insights_Newsletter__c,Press_Releases__c from Lead where Email IN :newLeads.KeySet()]) {
            //adds the incoming lead to a set that will be deleted further down
            leadsToDelete.put(newLeads.get(leadB.email).ID,newLeads.get(leadB.Email));   
                    
            //updates fields in existing leads
            leadB.HasOptedOutOfEmail = false;
            leadB.Press_Releases__c = true;
            leadB.Insights_Newsletter__c = true;
            leadB.Product_Announcements__c = true;
            leadB.Blog__c =true;
            leadB.Marketing_Opt_Out__c = false;
            if(leadB.Insights_Newsletter__c == false || leadB.Press_Releases__c == false || leadB.HasOptedOutOfEmail == true){
            existingLeads.add(leadB);
            }
        }
        if(existingLeads.size()>0) {
            update existingLeads;
        }
        //finds existing contacts where their email equals the incoming leads
        for(Contact contactA : [select ID, Name, Email, HasOptedOutofEmail, Insights_Newsletter__c, Press_Releases__c from Contact where Email IN :newLeads.keySet()]) {
            
            //adds the lead to a set to be deleted below
            
            	if(!leadsToDelete.containsKey(newLeads.get(contactA.Email).ID)) {
            		leadsToDelete.put(newLeads.get(contactA.Email).ID,newLeads.get(contactA.Email));
            	}
            
            
            //updates the existing contact          
            contactA.HasOptedOutOfEmail = false;
            contactA.Insights_Newsletter__c = True;
            contactA.Press_Releases__c = True;
            contactA.Product_Announcements__c = true;
            contactA.Blog__c = true;
            if(contactA.Insights_Newsletter__c == false || contactA.Press_Releases__c == false || contactA.HasOptedOutOfEmail == true) {
            existingContacts.add(contactA);
            }
        }
        if(existingContacts.size()>0) {
            update existingContacts;
        }
        
        if(leadsToDelete.size()>0) {
            //delete leadsToDelete.values();
            Database.delete(leadsToDelete.values());
           
            
        }
        
    }

}

 

 

jkucerajkucera

For updates in a trigger, I apply them in a before trigger usually, which avoids the issue.  For things like deletes, I typically use an @future method in a class to delete the leads.  This gets around the error you saw.

andyKal10andyKal10

Hey John,

The code below is now working. I got to this point by starting with your suggestion above of using @future annotation.

This led to a save error because, as I learned from you elsewhere in the boards, you cannot use arrays of sObjects with @future....Instead you have to pass in IDs and then search. So, I did this and got it to work, but decided to try removing @future just to see what would happen, and it still works. So, it seems that passing IDs rather than sObjects is how to avoid the error discussed above. I have decided to stick with and After Insert trigger for now because the trigger is designed to work only on leads that are being generated from Web-to-Lead, and I am not sure how the error thrown to prevent the insert of a duplicate lead would effect people filling out the webform.

 

Any impressions you could pass along would be appreciated as I am only a beginner. I have only programmed in Apex, don't really understand Annotations etc.

 

Thanks,

Andy

 

 

public with sharing class leadHandler {
	
    Public Static Void leadDeDuper(Map<String,String> newLeads) {
        Set<String> leadsToDelete = new Set<String>();
        List<Lead> leadsToDeleteList = new List<Lead>();
        List<Lead> existingLeads = new List<Lead>();
        List<Contact> contactsToDelete = new List<Contact>();
        List<Contact> existingContacts = new List<Contact>();
        
        //finds existing Leads where their email equals the incoming Lead
        for(Lead leadB : [select Id, Name, Blog__c,Email,HasOptedOutofEmail,Product_Announcements__c, MarketingCampaign__c, Insights_Newsletter__c,Press_Releases__c from Lead where Email IN :newLeads.KeySet()]) {
            //adds the incoming lead to a set that will be deleted further down
            leadsToDelete.add(newLeads.get(leadB.email));   
                    
            //updates fields in existing leads
            leadB.HasOptedOutOfEmail = false;
            leadB.Press_Releases__c = true;
            leadB.Insights_Newsletter__c = true;
            leadB.Product_Announcements__c = true;
            leadB.Blog__c =true;
            leadB.Marketing_Opt_Out__c = false;
           
            existingLeads.add(leadB);
        }
        
        if(existingLeads.size()>0) {
            update existingLeads;
        }
        //finds existing contacts where their email equals the incoming leads
        for(Contact contactA : [select ID, Name, Email, HasOptedOutofEmail, Insights_Newsletter__c, Press_Releases__c from Contact where Email IN :newLeads.keySet()]) {
            
            //adds the lead to a set to be deleted below
            leadsToDelete.add(newLeads.get(contactA.Email));
            
            //updates the existing contact          
            contactA.HasOptedOutOfEmail = false;
            contactA.Insights_Newsletter__c = True;
            contactA.Press_Releases__c = True;
            contactA.Product_Announcements__c = true;
            contactA.Blog__c = true;
            
            existingContacts.add(contactA);
        }
       
        if(existingContacts.size()>0) {
            update existingContacts;
        }
        
        if(leadsToDelete.size()>0) {
        	for(Lead dLead : [Select ID from Lead where ID IN:leadsToDelete]) {
        		leadsToDeleteList.add(dLead);
        	}
            delete leadsToDeleteList;
        }
        
    }

}