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
RajbharathRajbharath 

Need help in bulkifying this code

I wrote the following code for Lead conversion, but I know that it is not properly bulkified. I have tried to bulkify it, but facing some issues.  Please guide me on how to bulkify this code, so that I can use it as reference in the future.
 
public class LeadInsertTriggerHandler {

public static void AfterInsert(List<Lead> lstLeads)
{
    LeadStatus convertStatus = [select MasterLabel from LeadStatus where IsConverted = true limit 1];
    List<Database.LeadConvert> leadConverts = new List<Database.LeadConvert>();

    for (Lead lead: lstLeads) {
        if (!lead.isConverted) {
            Database.LeadConvert lc = new Database.LeadConvert();

            lc.setLeadId(lead.Id);
            lc.setConvertedStatus(convertStatus.MasterLabel);
            lc.setDoNotCreateOpportunity(TRUE);

            List<account> obj_account = [select id from account where 
                                         Email_and_SiteID__c= :lead.Email_and_SiteID__c];
            if(obj_account.size()>0)
            {
                lc.setAccountId(obj_account[0].id);
            }
                leadConverts.add(lc);
            }
            }

            if (!leadConverts.isEmpty()) {
            List<Database.LeadConvertResult> lcr = Database.convertLead(leadConverts);
        }
    }

}

 
Best Answer chosen by Rajbharath
Vikash GoyalVikash Goyal
Hi Rajbharath, 

You can try with this :
 
public class LeadInsertTriggerHandler {

public static void AfterInsert(List<Lead> lstLeads){   
    
    List<String> lstEmailSiteIds = new List<String>();
    for (Lead lead: lstLeads) {
        lstEmailSiteIds.add(lead.Email_and_SiteID__c);
    }

    List<Account> lstAccounts = new List<Account>([SELECT Id, Email_and_SiteID__c FROM Account WHERE Email_and_SiteID__c IN : lstEmailSiteIds]);
    Map<String, List<Account>> accountMap = new Map<String, List<Account>>();

    for(Account acc : lstAccounts){
        if(!accountMap.containsKey(acc.Email_and_SiteID__c)){
            accountMap.put(acc.Email_and_SiteID__c, new List<Account>());
        }
        accountMap.get(acc.Email_and_SiteID__c).add(acc);
    }

    LeadStatus convertStatus = [select MasterLabel from LeadStatus where IsConverted = true limit 1];
    List<Database.LeadConvert> leadConverts = new List<Database.LeadConvert>();

    for (Lead lead: lstLeads) {
        if (!lead.isConverted) {
            Database.LeadConvert lc = new Database.LeadConvert();

            lc.setLeadId(lead.Id);
            lc.setConvertedStatus(convertStatus.MasterLabel);
            lc.setDoNotCreateOpportunity(TRUE);

            List<account> obj_account = accountMap.get(lead.Email_and_SiteID__c);
            
            if(obj_account != null && obj_account.size()>0)
            {
                lc.setAccountId(obj_account[0].id);
            }
                leadConverts.add(lc);
            }
            }

            if (!leadConverts.isEmpty()) {
            List<Database.LeadConvertResult> lcr = Database.convertLead(leadConverts);
        }
    }

}

 

All Answers

Vikash GoyalVikash Goyal
Hi Rajbharath,

You can bulkify the code as follows :
 
public class LeadInsertTriggerHandler {

public static void AfterInsert(List<Lead> lstLeads){   
    
    List<String> lstEmailSiteIds = new List<String>();
    for (Lead lead: lstLeads) {
        lstEmailSiteIds.add(lead.Email_and_SiteID__c);
    }

    List<Account> lstAccounts = new List<Account>([SELECT Id, Email_and_SiteID__c FROM Account WHERE Email_and_SiteID__c IN : lstEmailSiteIds]);
    Map<String, List<Account>> accountMap = new Map<String, List<Account>>();

    for(Account acc : lstAccounts){
        if(!accountMap.containsKey(acc.Email_and_SiteID__c)){
            accountMap.put(acc.Email_and_SiteID__c, new List<Account>());
        }
        accountMap.get(acc.Email_and_SiteID__c).add(acc);
    }

    LeadStatus convertStatus = [select MasterLabel from LeadStatus where IsConverted = true limit 1];
    List<Database.LeadConvert> leadConverts = new List<Database.LeadConvert>();

    for (Lead lead: lstLeads) {
        if (!lead.isConverted) {
            Database.LeadConvert lc = new Database.LeadConvert();

            lc.setLeadId(lead.Id);
            lc.setConvertedStatus(convertStatus.MasterLabel);
            lc.setDoNotCreateOpportunity(TRUE);

            List<account> obj_account = accountMap.get(lead.Email_and_SiteID__c);
            
            if(obj_account.size()>0)
            {
                lc.setAccountId(obj_account[0].id);
            }
                leadConverts.add(lc);
            }
            }

            if (!leadConverts.isEmpty()) {
            List<Database.LeadConvertResult> lcr = Database.convertLead(leadConverts);
        }
    }

}

Please let me know if that helps you.
If it helps don't forget to mark this as a best answer!!!

Thanks 
Vikash G 
Niraj Kr SinghNiraj Kr Singh
Hi Rajbharath,

Plz try this code and let me know if it helps you.
public class LeadInsertTriggerHandler {

	public static void AfterInsert(List<Lead> lstLeads)
	{
		LeadStatus convertStatus = [select MasterLabel from LeadStatus where IsConverted = true limit 1];
		List<Database.LeadConvert> leadConverts = new List<Database.LeadConvert>();
		
		//Here Code for bulkifying
		Map<String, List<Account>> mapAccounts = new Map<String, List<Account>>();
		Set<String> setEmails = new Set<String>();
		for(Lead objLead : lstLeads) {
			setEmails.add(objLead.Email_and_SiteID__c);
		}
		
		if(!setEmails.isEmpty()) {
			for(Account objAccount = [select id, Email_and_SiteID__c from account where Email_and_SiteID__c In: setEmails]) {
				if(mapAccounts.containsKey(objAccount.Email_and_SiteID__c)) {
					mapAccounts.get(objAccount.Email_and_SiteID__c).add(objAccount);
				}
				else {
					mapAccounts.put(objAccount.Email_and_SiteID__c, new List<Account>{objAccount});
				}
			}
		}
		
		for (Lead lead: lstLeads) {
			if (!lead.isConverted) {
				Database.LeadConvert lc = new Database.LeadConvert();

				lc.setLeadId(lead.Id);
				lc.setConvertedStatus(convertStatus.MasterLabel);
				lc.setDoNotCreateOpportunity(TRUE);

				//bulkifying here
				if(mapAccounts.size()>0 && mapAccounts.containsKey(lead.Email_and_SiteID__c))
				{
					lc.setAccountId(mapAccounts.get(lead.Email_and_SiteID__c)[0].id);
				}
				leadConverts.add(lc);
			}
		}

		if (!leadConverts.isEmpty()) {
			List<Database.LeadConvertResult> lcr = Database.convertLead(leadConverts);
		}
    }

}


Thanks
Niraj
RajbharathRajbharath
Thanks you so much guys. your both code gave me the picture of where I am going wrong. I will implement this tomorrow.
RajbharathRajbharath
@Vikash Goyal  I am facing the following error with your code. It's throwing a null pointer exception. Please see the attached screenshot.

User-added image
RajbharathRajbharath
@Vikash Apex trigger lead_onConvert caused an unexpected exception, contact your administrator: lead_onConvert: execution of AfterInsert caused by: System.NullPointerException: Attempt to de-reference a null object: Class.LeadInsertTriggerHandler.AfterInsert: line 33, column 1
RajbharathRajbharath
@Niraj Singh

While trying to work with your code, I am gettting this error at Line 16: Expecting ';' but was: ')'

I think the IF statement should be with in the class. Tried doing that but facing issues. Any pointers on resolving that would be helpful, so that I can test the lead conversion logic.
Niraj Kr SinghNiraj Kr Singh
Hi Rajbharath,
This was typo, you update this line:
for(Account objAccount = [select id, Email_and_SiteID__c from account where Email_and_SiteID__c In: setEmails]) {

By (We have to use ":" instead of "=" in for loop)
for(Account objAccount : [select id, Email_and_SiteID__c from account where Email_and_SiteID__c In: setEmails]) {
Vikash GoyalVikash Goyal
Hi Rajbharath, 

You can try with this :
 
public class LeadInsertTriggerHandler {

public static void AfterInsert(List<Lead> lstLeads){   
    
    List<String> lstEmailSiteIds = new List<String>();
    for (Lead lead: lstLeads) {
        lstEmailSiteIds.add(lead.Email_and_SiteID__c);
    }

    List<Account> lstAccounts = new List<Account>([SELECT Id, Email_and_SiteID__c FROM Account WHERE Email_and_SiteID__c IN : lstEmailSiteIds]);
    Map<String, List<Account>> accountMap = new Map<String, List<Account>>();

    for(Account acc : lstAccounts){
        if(!accountMap.containsKey(acc.Email_and_SiteID__c)){
            accountMap.put(acc.Email_and_SiteID__c, new List<Account>());
        }
        accountMap.get(acc.Email_and_SiteID__c).add(acc);
    }

    LeadStatus convertStatus = [select MasterLabel from LeadStatus where IsConverted = true limit 1];
    List<Database.LeadConvert> leadConverts = new List<Database.LeadConvert>();

    for (Lead lead: lstLeads) {
        if (!lead.isConverted) {
            Database.LeadConvert lc = new Database.LeadConvert();

            lc.setLeadId(lead.Id);
            lc.setConvertedStatus(convertStatus.MasterLabel);
            lc.setDoNotCreateOpportunity(TRUE);

            List<account> obj_account = accountMap.get(lead.Email_and_SiteID__c);
            
            if(obj_account != null && obj_account.size()>0)
            {
                lc.setAccountId(obj_account[0].id);
            }
                leadConverts.add(lc);
            }
            }

            if (!leadConverts.isEmpty()) {
            List<Database.LeadConvertResult> lcr = Database.convertLead(leadConverts);
        }
    }

}

 
This was selected as the best answer
RajbharathRajbharath
Thanks to both of you. Learned a lot by seeing the code. Both of your code works well. kudos guys. Sorry I think I can select only one as the best answer, but the code was accurate by both of you.
RajbharathRajbharath
@Niraj @Vikash

Guys I have some questions further about the code above. Suppose if there are 500,000 existing records in Account object, and If i am trying to upload some 10000 records into the Leads object, then according to the above code it should search for existing records, but the trigger will throw an exception right?

How to approach this use case? Is it better to write a batch apex and schedule it to run every day? Let me know your thoughts
Niraj Kr SinghNiraj Kr Singh
Hi Rajbharat

For this type of use case, you have to go with apex batch class. Where you can reuse the same code as well.

Like this:

global class LeadConvertBatchJob implements Database.Batchable<sObject> 
{
    global Database.QueryLocator start(Database.BatchableContext BC) 
    {
        String query = 'SELECT Id FROM Lead';. // Add here other required fields and WHERE condition created before one hour and not convert ed.
        
        return Database.getQueryLocator(query);
    }
    global void execute(Database.BatchableContext BC, List<Lead> scope) 
    {
        afterInsert(scope);
    }
    global void finish(Database.BatchableContext BC) {
    }

   private void afterInsert(List<Lead> lstLeads) {
         // Simply add all trigger logic here what we have mentioned above in previous post.
    }
}

 **********************************************************
First deactivate the above trigger which created for this functionality.
 And execute this batch from developer console by using this code.

Database.excutBatch( new <Batch Class Name >(), 2000 ); // plz check Syntex from ur side once.

Note:Plz add WHERE condition properly in SOQL to get created record just before.

 Let me know if you found any issue.