+ Start a Discussion
AviKesariAviKesari 

Too many SOQL queries : 101, test class fails

Hi All,

I have trigger on after insert and after update, below is my handler class.

If i create a task from contact(is a required field on page layout) it fails because whatID is null. So I'm trying to query to get the whatID based on whoID.

If i create a task from account, works fine because whoid and whatid are not null.

public with sharing class TaskTriggerHandler {
    
    private boolean trigger_isExecuting = false;
    
    public TaskTriggerHandler(){
        
    }
    
    public void OnAfterInsert(Task[] newObjects){
        // EXECUTE AFTER INSERT LOGIC       updateAccountActivityFields(newObjects);
    }
    
    public void OnAfterUpdate(Task[] oldObjects, Task[] updatedObjects, Map<ID, Task> ObjectMap){
        //EXECUTE AFTER UPDATE LOGIC
        updateAccountActivityFields(updatedObjects);
    }
    

     public void updateAccountActivityFields(Task[] taskRecords){
      
        // find task record type 
        RecordType taskRec = [SELECT Id FROM RecordType WHERE SobjectType ='Task' AND DeveloperName ='Task_Record_Type'];
        
        List<Account> accountsToUpdate = new List<Account>();
        Account a;
       
        //Get all the contactIds and accountIds of the task being inserted/updated
        for(Task tk : [SELECT Id, LastModifiedBy.name, type, LastModifiedDate, CreatedDate, RecordTypeId, whoid, whatid FROM task WHERE id in :taskRecords]){
            if(tk.RecordTypeId == taskRec.Id  && tk.Whoid!=null){
                
                // query to get account ID from contact:whoID 
                a = new Account(Id = [SELECT AccountId FROM Contact  WHERE Id =: tk.WhoId Limit 1].AccountId);
                //convert task's CreatedDate, datetime to date
                Date createdDateJustDate = date.newinstance(tk.CreatedDate.year(), tk.CreatedDate.month(), tk.CreatedDate.day());
        
                //update the activity fields on account with Task's lastModifiedDate and LastModifiedBy based on Task Type
                if(tk.type=='Face 2 Face Meeting' || tk.type=='Lunch'){
                    a.Last_Face_to_Face_Activity__c = createdDateJustDate;
                    a.Last_Visited_By__c = tk.LastModifiedBy.name;
      
                }
                else{
                    a.Last_Call_Activity__c =  createdDateJustDate;
                    
                }
                
                accountsToUpdate.add(a);
               
            }
        }
        
       if(!accountsToUpdate.isEmpty())
            Update accountsToUpdate;

My test Class :

Please help!!
    
    public void OnAfterUpdate(Task[] oldObjects, Task[] updatedObjects, Map<ID, Task> ObjectMap){
        //EXECUTE AFTER UPDATE LOGIC
        System.debug('SAFELITE_DEBUG:TaskTriggerHandler:OnAfterUpdate:: updatedObjects=' + updatedObjects);
        updateAccountActivityFields(updatedObjects);
    }
    

     public void updateAccountActivityFields(Task[] taskRecords){
        /* when a task of RecordType(Safelite_Task_Record_Type) is created/updated either from Account or Contact then 
        update Account fields : Last_Face_to_Face_Activity__c, Last_Visited_By__c & Last_Call_Activity__c based on task type
        */
        System.debug('SAFELITE_DEBUG:TaskTriggerHandler:updateAccountActivityFields:: taskRecords=' + taskRecords);

        // find task record type 
        RecordType taskRec = [SELECT Id FROM RecordType WHERE SobjectType ='Task' AND DeveloperName ='Safelite_Task_Record_Type'];
        System.debug('SAFELITE_DEBUG:TaskTriggerHandler:updateAccountActivityFields:: taskRec.Id=' + taskRec.Id);
        
        List<Account> accountsToUpdate = new List<Account>();
        Account a;
         
        //Map of Account IDs and Accounts
        Map<id,account> accMap = new Map<id,account>();
       
        //Get all the contactIds and accountIds of the task being inserted/updated
        for(Task tk : [SELECT Id, LastModifiedBy.name, type, LastModifiedDate, CreatedDate, RecordTypeId, whoid, whatid FROM task WHERE id in :taskRecords]){
            if(tk.RecordTypeId == taskRec.Id  && tk.Whoid!=null){
                
                a = new Account(Id = [SELECT AccountId FROM Contact  WHERE Id =: tk.WhoId LIMIT 100].AccountId);
                              
                System.debug('SAFELITE_DEBUG:TaskTriggerHandler:updateAccountActivityFields:: tk.WhatId=' + tk.WhatId);
                
                //convert task's CreatedDate, datetime to date
                Date createdDateJustDate = date.newinstance(tk.CreatedDate.year(), tk.CreatedDate.month(), tk.CreatedDate.day());
                System.debug('SAFELITE_DEBUG:TaskTriggerHandler:updateAccountActivityFields:: createdDateJustDate=' + createdDateJustDate);
                
                //update the activity fields on account with Task's lastModifiedDate and LastModifiedBy based on Task Type
                if(tk.type=='Face 2 Face Meeting' || tk.type=='Lunch'){
                    a.Last_Face_to_Face_Activity__c = createdDateJustDate;
                    a.Last_Visited_By__c = tk.LastModifiedBy.name;
                    accountsToUpdate.add(a);
                    System.debug('SAFELITE_DEBUG:TaskTriggerHandler:updateAccountActivityFields:: Last_Face_to_Face_Activity__c=' + a.Last_Face_to_Face_Activity__c);
                    System.debug('SAFELITE_DEBUG:TaskTriggerHandler:updateAccountActivityFields:: Last_Visited_By__c=' + a.Last_Visited_By__c);
                }
                else{
                    a.Last_Call_Activity__c =  createdDateJustDate;
                    accountsToUpdate.add(a);
                    System.debug('SAFELITE_DEBUG:TaskTriggerHandler:updateAccountActivityFields:: Last_Call_Activity__c=' + a.Last_Call_Activity__c);
                }
                //Populate accMap with the Account IDs and Account record
                accMap.put(a.id,a);
               
            }
        }
        
         if(!accMap.isEmpty()){
            Update accMap.values();
        }
            
    }
}

My Test Class:
 static testMethod void testAdminUserwithTask() {
        
        // Next make sure that a System Admin *can* delete an attachment
        Profile adminProf = [select id from profile where name='System Administrator']; 
        User au = new User(alias = 'Admint', email='AdminUser@asdahsdjkhkjashdjasd.com',emailencodingkey='UTF-8',FirstName='Admin',
                           lastname='task',languagelocalekey='en_US',localesidkey='en_US',profileid = adminProf.Id,
                           timezonesidkey='America/Los_Angeles',username='AdminUser@asdahsdjkhkjashdjasd.com');
        // Switch current user to System Admin user
        System.runAs(au) {
            // Create test data (a new Account with an Attachment)
            Account a = new Account(Name='Testtasking');
            insert a;
            Contact con = new Contact(LastName='Test',FirstName='asdasd',Email='asdasd@adsasd.com') ;
            insert con ; 
            List<Task> tasks = new List<Task>{};
                for(Integer i = 0; i < 200; i++) 
            {
                Task t = new Task(Subject='Donni'+i,Status='New',Priority='Normal',Type='Phone Call', whoId =con.Id, whatId = a.Id );
                tasks.add(t);
            }
            test.startTest();
            insert tasks;
            test.stopTest();
            
            try {
                delete tasks;
            } catch (Exception e) {
                
            }
            
        }
    }
 
Khan AnasKhan Anas (Salesforce Developers) 
Hi,

Greetings to you!

Rewrite code that executes queries inside for loops by moving the query outside of the loop and extending it to query all necessary data.

This error appears when you exceed the Execution Governors Limit (you can run up to a total 100 SOQL queries in a single call or context): https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_gov_limits.htm

To fix the issue, change your code so that the number of SOQL fired is less than 100.
If you need to change the context, you can use @future annotation which will run the code asynchronously.
 
Best practices to avoid exceeding the Governors Limit:

Since Apex runs on a multi-tenant platform, the Apex runtime engine strictly enforces limits to ensure code doesn't monopolize shared resources.
 
Reference: https://help.salesforce.com/articleView?id=000181404&type=1

I hope it helps you.

Kindly let me know if it helps you and close your query by marking it as solved so that it can help others in the future. It will help to keep this community clean.

Thanks and Regards,
Khan Anas
$hwet@$hwet@
Hi  AviKesari ,

You have to reduce the number of SOQL queries fron the single thread because it is hitting the limit. You can do that by reducing it in may ways. Below is one example. For getting the record type, don't use query insted you can use below code:

 Old Query : 
RecordType taskRec = [SELECT Id FROM RecordType WHERE SobjectType ='Task' AND DeveloperName ='Safelite_Task_Record_Type'];

No query required: 
Id devRecordTypeId = Schema.SObjectType.Account.getRecordTypeInfosByName().get('Development').getRecordTypeId();
Here, 'Development' is the record type's name.

https://developer.salesforce.com/forums/?id=906F0000000937iIAA