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
Jaye LoweJaye Lowe 

too many soql queries - lead conversion

I inherited this code and it seems to be causing a lead conversion to fail, but only becuase it's stopping at too many soql queries. Can anyone help me optimize this code to prevent this issue. Thanks. 
 
public with sharing class OpportunityStageHandler {
    
    public OpportunityStageHandler() {
    }

    public static void init(List<Opportunity> opportunities){
        
        String debug = 'Opportunity Stage Handler';
        
        insertOpportunityStageDurations(opportunities);
    }

    public static void insertOpportunityStageDurations(List<Opportunity> opportunities){

        List<Opportunity_Stage_Duration__c> existing = new List<Opportunity_Stage_Duration__c>();
        Map<Id, Opportunity_Stage_Duration__c> existingMap = new Map<Id, Opportunity_Stage_Duration__c>();
        Map<Id, String> existingStageMap = new Map<Id, String>();
        List<Opportunity_Stage_Duration__c> inserts = new List<Opportunity_Stage_Duration__c>();
        DateTime stageStart = DateTime.now();

        existing = [SELECT Id, 
                           Stage__c,
                           Stage_Started__c,
                           Stage_Ended__c,
                           Opportunity__r.Id
                    FROM Opportunity_Stage_Duration__c
                    WHERE Opportunity__c IN :opportunities
                    AND Stage_Ended__c = null];
        
        for(Opportunity_Stage_Duration__c opportunityStageDuration : existing){            
            existingMap.put(opportunityStageDuration.Opportunity__r.Id, opportunityStageDuration);
            existingStageMap.put(opportunityStageDuration.Opportunity__r.Id, opportunityStageDuration.Stage__c);
        }       
        
        for(Opportunity opportunity : opportunities){
            if(existingStageMap.get(opportunity.Id) == null || existingStageMap.get(opportunity.Id) != opportunity.StageName){
                Opportunity_Stage_Duration__c osd = new Opportunity_Stage_Duration__c();

                Integer stageLength = opportunity.StageName.length() + 3;
                Integer nameLength = opportunity.Name.length();

                if(stageLength + nameLength > 80){                    
                    Integer trim = stageLength + nameLength - 80;
                    Integer endIndex = nameLength - trim - 1;
                    osd.Name = (opportunity.Name.substring(0, endIndex)) + ' - ' + opportunity.StageName;
                }else{
                    osd.Name = opportunity.Name + ' - ' + opportunity.StageName;
                }
                
                osd.Opportunity__c = opportunity.Id;        
                osd.Stage_Started__c = stageStart;
                osd.Stage__c = opportunity.StageName;
                inserts.add(osd);
            }
        }

        insert inserts;

        updateOpportunityStageDurations(opportunities, existingMap);
    }

    public static void updateOpportunityStageDurations(List<Opportunity> opportunities,
                                                       Map<Id, Opportunity_Stage_Duration__c> existingMap){
        
        List<Opportunity_Stage_Duration__c> updates = new List<Opportunity_Stage_Duration__c>();
        DateTime stageEnded = DateTime.now();

        for(Opportunity opportunity : opportunities){
            if(existingMap.get(opportunity.Id) != null &&
               existingMap.get(opportunity.Id).Stage__c != opportunity.StageName){
                
                Opportunity_Stage_Duration__c osd = existingMap.get(opportunity.Id);

                osd.Stage_Ended__c = stageEnded;
                Date startDay = Date.newInstance(osd.Stage_Started__c.year(), osd.Stage_Started__c.month(), osd.Stage_Started__c.day());
                Date endDay = Date.newInstance(stageEnded.year(), stageEnded.month(), stageEnded.day());
                osd.Stage_Duration__c = startDay.daysBetween(endDay);
                updates.add(existingMap.get(opportunity.Id));
            }
        }

        update updates;
    }

}

 
SwethaSwetha (Salesforce Developers) 
Hi Jaye,

I see you are having one SOQL 
SELECT Id, Stage__c, Stage_Started__c, Stage_Ended__c, Opportunity__r.Id FROM Opportunity_Stage_Duration__c WHERE Opportunity__c IN :opportunities AND Stage_Ended__c = null

The error you are seeing is because of the governor limit (https://developer.salesforce.com/docs/atlas.en-us.salesforce_app_limits_cheatsheet.meta/salesforce_app_limits_cheatsheet/salesforce_app_limits_platform_apexgov.htm) enforced on the query. The total number of records retrieved by SOQL queries is 50,000. If it exceeds the limit you will see the Too many query rows: 50001 error.

You need to setup debug logs to Identify the Soql with aggregation which is contributing to this limit and then fix it. Track the output of each soql : not just the whole soql but the result of inner queries as well.

See articles: https://help.salesforce.com/articleView?id=000325247&language=en_US%C2%A0&type=1&mode=1

https://help.salesforce.com/articleView?id=000325257&language=en_US&type=1&mode=1

The below links will give a better understanding of the troubleshooting approach of scenarios with same error
https://salesforce.stackexchange.com/questions/105609/system-limitexception-too-many-query-rows-50001-even-though-soql-has-limit-10

https://salesforce.stackexchange.com/questions/40916/too-many-query-rows-50001

https://stackoverflow.com/questions/9984349/limitexception-too-many-query-rows-50001-from-with-count-aggregate-function

If this information helps, please mark the answer as best. Thank you