0

This is my apex class

public class ContactTriggerOperations {
    Public static List<Update_Team__mdt> metaDataList = [SELECT Id,Team__c,Sr_No__c, Title__c FROM Update_Team__mdt where IsJobLevel__c =false ORDER BY Sr_No__c ASC];
    Public static List<Update_Team__mdt> jobLevelMetaDataList = [SELECT Id,Sr_No__c,Exact_Title__c,Job_Level__c, Title__c FROM Update_Team__mdt where IsJobLevel__c=true ORDER BY Sr_No__c ASC];
    Public static List<Contact_Import_Rule__mdt > customMetadataInquiry = [SELECT Id,Billing_Country__c,Billing_State_Code__c,Industry__c,Region__c,Revenue_Range__c,User_Id__c,Sr_No__c FROM Contact_Import_Rule__mdt ORDER BY Sr_No__c ASC];
    Public static Map<Id, Contact >oldContactMap= (Map<Id, Contact >)Trigger.oldMap; 
    Public static List< Contact >oldContactList= (List< Contact >)Trigger.old;
    Public static Map<Id, Contact >newContactMap= (Map<Id, Contact >)Trigger.newMap; 
    Public static List< Contact >newContactList= (List< Contact >)Trigger.new; 
    
    /*purpose: to update the contact team based on conditions on contact's insertion 
     *Return: void
     *params: newContactList
     */
    public static void beforeInsert()
    {
        ContactTriggerOperations.updateTeam(newContactList,null);
        ContactTriggerOperations.updateContactOwner(newContactList,null);
        ContactTriggerOperations.updateJobLevel(newContactList,null);
    }
    
    /*purpose: to update the contact team based on conditions on contact's updation 
     *Return: void
     *params: newContactList
     */
    public static void beforeUpdate()
    {
        ContactTriggerOperations.updateTeam(newContactList,oldContactMap);
        ContactTriggerOperations.updateContactOwner(newContactList,oldContactMap);
        ContactTriggerOperations.updateJobLevel(newContactList,oldContactMap);
    }
    
    /*purpose: to update the contact team 
     *Return: void
     *params: newContactList,oldContactMap
     */
    public static void updateTeam(List<Contact> newContactList, Map<Id, Contact> oldContactMap)
    {
        string Title;
        //loop through all records in Trigger.new collection
        for(Contact c: newContactList)
        {
            if(c.Title!= null && (oldContactMap==null || (oldContactMap!=null && c.Title != oldContactMap.get(c.Id).Title) ))
            {
                Title=c.Title.toLowerCase(); //convert title to lower case
                if(Title!=null)
                {
                    //method to get team and store it in string
                    String ContactTeam=ContactTriggerOperations.getTeam(Title);
                    
                    if(!String.isBlank(ContactTeam))
                    {
                        c.Team__c=ContactTeam;
                    }
                    else
                    {
                        c.Team__c='Other Non-IT';
                    }
                }
                
            }
            else if(c.Title== null && (oldContactMap==null || (oldContactMap!=null && c.Title != oldContactMap.get(c.Id).Title) ))
            {
                c.Team__c='Unknown';
            }
        }
    }
    
    public static void updateJobLevel(List<Contact> newContactList, Map<Id, Contact> oldContactMap)
    {
        string Title;
        //loop through all records in Trigger.new collection
        for(Contact c: newContactList)
        {
            if(c.Title!= null && (oldContactMap==null || (oldContactMap!=null && c.Title != oldContactMap.get(c.Id).Title) ))
            {
                Title=c.Title.toLowerCase(); //convert title to lower case
                if(Title!=null)
                {
                    //method to get team and store it in string
                    
                    String ContactJobLevel=ContactTriggerOperations.getJobLevel(Title);
                    if(!String.isBlank(ContactJobLevel))
                    {
                        c.Job_Level__c =ContactJobLevel;
                    }
                    else
                    {
                        c.Job_Level__c= 'Individual Contributor';
                    }
                    
                }
                
            }
            else if((c.Title== null || c.Title=='None') && (oldContactMap==null || (oldContactMap!=null && c.Title != oldContactMap.get(c.Id).Title) ))
            {
                c.Job_Level__c='Unknown';
            }
        }
    }
    
    /*purpose: to get the value of ownerId 
     *Return: Team
     *params: Title
     */
    public static string getTeam(String Title)
    {
        string team; //string to store team name
        system.debug('TitleSize'+metaDataList.size());
        if(metaDataList!=null && !metaDataList.isEmpty())
        {
            //loop through all custom metadata records
            for(Update_Team__mdt cm : metaDataList)
            {
                String Titles=cm.Title__c; //string to store titles
                
                List<String> listTitle = Titles.split(';'); //split the titles and store it in list
                
                if(team==null)
                {
                    for(String str : listTitle)
                    {
                        if(Title.contains(str) && (cm.Sr_No__c!=16 || cm.Sr_No__c!=17 || cm.Sr_No__c!=19 ))
                        {
                            team= cm.Team__c;
                            if(team!=null)
                            {
                                break; //break statement to stop for loop
                            }
                        }
                        else if(Title.contains(str) && cm.Sr_No__c==16 && !Title.contains(System.Label.security))
                        {
                            team= cm.Team__c;
                            if(team!=null)
                            {
                                break; //break statement to stop for loop
                            }
                        }
                        else if(cm.Sr_No__c==17)
                        {
                            system.debug('Contain'+str);
                            if((Title.contains(str)) || (Title.contains(System.Label.development) && (!Title.contains(System.Label.business_development) && !Title.contains(System.Label.corporate_development) && !Title.contains(System.Label.Product_Development) 
                                                                                                      && !Title.contains(System.Label.research_and_development) && !Title.contains(System.Label.research_development) && !Title.contains(System.Label.technology_development) ) ))
                            {
                                team= cm.Team__c;
                                if(team!=null)
                                {
                                    break; //break statement to stop for loop
                                }
                            }
                        }
                        else if(Title.contains(str) && cm.Sr_No__c==19 && !Title.contains(System.Label.assistant))
                        {
                            team= cm.Team__c;
                            if(team!=null)
                            {
                                break; //break statement to stop for loop
                            }
                        }             
                    }
                }
                else
                {
                    break; //break statement to stop for loop
                }
            }
        }
        return team; 
    }
    
    /*purpose: to get the value of ownerId 
     *Return: Team
     *params: Title
     */
    public static string getJobLevel(String Title)
    {
        string jobLevel; //string to store job level name
        system.debug('jobSize'+jobLevelMetaDataList.size());
        if(jobLevelMetaDataList!=null && !jobLevelMetaDataList.isEmpty())
        {
            //loop through all custom metadata records
            for(Update_Team__mdt cm : jobLevelMetaDataList)
            {
                String Titles=cm.Title__c; //string to store titles
                system.debug('Hello');
                List<string> listTitles = Titles.split(';'); //split the titles and store it in list
                if(jobLevel==null && !String.isBlank(Title))
                {
                    for(String str:listTitles)
                    {
                    if((cm.Exact_Title__c==Title || Title.contains(str) || (Title.contains('chief') && Title.contains('officer') )) && !Title.contains('assistant') && cm.Sr_No__c==25 )
                    {
                        jobLevel=cm.Job_Level__c;
                        if(jobLevel != null)
                        {
                            break;
                        }
                    }
                    else if(Title.contains(str) && (!Title.contains('assistant to') || !Title.contains('executive assistant')) && (cm.Sr_No__c==26 || cm.Sr_No__c==27))
                    {
                        system.debug('Hiii');
                        jobLevel=cm.Job_Level__c;
                        if(jobLevel != null)
                        {
                            break;
                        }
                    }
                    else if(Title.contains(str) && cm.Sr_No__c==28)
                    {
                        jobLevel=cm.Job_Level__c;
                        if(jobLevel != null)
                        {
                            break;
                        } 
                    }
                    else if((Title=='Student'|| Title.contains(str)) && cm.Sr_No__c==29 )
                    {
                        jobLevel=cm.Job_Level__c;
                        if(jobLevel != null)
                        {
                            break;
                        } 
                    }
                }
                }
                else
                {
                    break;
                }

            }
        }
        return jobLevel; 
    }
    /*purpose: to update the contact owner 
     *Return: void
     *params: newContactList,oldContactMap
     */
    public static void updateContactOwner(List<Contact> newContactList, Map<Id, Contact> oldContactMap)
    {
        Set<Id> SetaccountIds = new Set<Id>(); //set to store account id
        Map<Id,Account> mapAccount;
        
        //loop through all records in Trigger.new collection
        for(Contact con:newContactList)
        {
            //check if contact has account
            if(con.AccountId!=null && con.Force_Ownership_Assignment__c==true && (oldContactMap==null || (oldContactMap!=null && con.Force_Ownership_Assignment__c != oldContactMap.get(con.Id).Force_Ownership_Assignment__c )))
            {
                SetaccountIds.add(con.AccountId);
            }
        }
        
        if(SetaccountIds!=null && !SetaccountIds.isEmpty())
        {
            mapAccount = new Map<Id,Account>([SELECT Id,BillingCountry,BillingCountryCode,Region__c,BillingStateCode,BillingState,Revenue_Range__c,Industry from Account WHERE Id IN :SetaccountIds]);
            //loop through all records in Trigger.new collection
            for(Contact contactRecord: newContactList)
            {
                Account accountRecord = mapAccount.get(contactRecord.AccountId); // get contact's account 
                
                if(contactRecord.AccountId!= null && accountRecord.BillingCountry !=null) 
                {
                    //get owner id and store it in string
                    String OwnerId=ContactTriggerOperations.getOwnerId
                        (accountRecord.BillingCountry,
                         accountRecord.BillingStateCode,
                         accountRecord.Region__c,
                         accountRecord.Revenue_Range__c,
                         accountRecord.Industry);
                    
                    if(!String.isBlank(OwnerId)) //check if OwnerId is not blank
                    {
                        contactRecord.OwnerId=OwnerId;
                        contactRecord.Force_Ownership_Assignment__c=false;
                    }
                }
            }
        }
    }
    
    /*purpose: to get the value of ownerId 
     *Return: ownerId
     *params: BillingCountry,StateCode,Region,Revenue,Industry
     */
    public static string getOwnerId(String BillingCountry,String StateCode,String Region,String Revenue,String Industry )
    {
        String ownerId; //string to store owner id
        
        //loop through all custom metadata records
        for(Contact_Import_Rule__mdt customMetaDataRecord:customMetadataInquiry)
        {
            if(customMetaDataRecord.Region__c != null && Region==customMetaDataRecord.Region__c && (customMetaDataRecord.Sr_No__c==1 || customMetaDataRecord.Sr_No__c==2 || customMetaDataRecord.Sr_No__c==3 ))
            {
                ownerId=customMetaDataRecord.User_Id__c;
                if(ownerId!=null)
                {
                    break; //break statement to stop for loop
                }
            }
            else if(customMetaDataRecord.Region__c == null && customMetaDataRecord.Billing_Country__c== BillingCountry  && !String.isBlank(StateCode) &&
                    (customMetaDataRecord.Sr_No__c==4 || customMetaDataRecord.Sr_No__c==5 || customMetaDataRecord.Sr_No__c==6 || customMetaDataRecord.Sr_No__c==7  ))
            {
                if(customMetaDataRecord.Billing_State_Code__c.contains(StateCode))
                {
                    ownerId=customMetaDataRecord.User_Id__c;
                    if(ownerId!=null)
                    {
                        break; //break statement to stop for loop
                    }
                }
            }
            else if(customMetaDataRecord.Region__c == null && customMetaDataRecord.Billing_Country__c== BillingCountry && !String.isBlank(StateCode) 
                    && customMetaDataRecord.Industry__c!=Industry && customMetaDataRecord.Revenue_Range__c==Revenue)
            {
                if(customMetaDataRecord.Billing_State_Code__c.contains(StateCode))
                {
                    ownerId=customMetaDataRecord.User_Id__c;
                    if(ownerId!=null)
                    {
                        break; //break statement to stop for loop
                    }
                }
            }
        }
        return ownerId;
    }
}
5

This has a ton of problems with it. You check for nulls for things that will never be null, you skip iterating over empty lists (which is harmless), you call a massive loop for every record when a map would have sufficed, etc. It's no wonder that this could have problems running in bulk.

I'm not sure how much work needs to be done to optimize, as you've not done any profiling on your code, but here's some hints for starting out.

        if(c.Title!= null && (oldContactMap==null || (oldContactMap!=null && c.Title != oldContactMap.get(c.Id).Title) ))

...

            if(Title!=null)

The second statement is always true; you already checked if title was not null, and toLowerCase can't return null.


    if(metaDataList!=null && !metaDataList.isEmpty())

The result of a query is never null, and iterating over an empty list is harmless.


                    if(Title.contains(str) && (cm.Sr_No__c!=16 || cm.Sr_No__c!=17 || cm.Sr_No__c!=19 ))

This will always be true if Title.contains(str), because if Sr_No__c = 16, it will not equal 17 (and same for 17 and 19). Use !(cm.Sr_No__c==16 || cm.Sr_No__c==17 || cm.Sr_No__c==19) instead.


getJobLevel literally runs a huge loop every time you call it, thus making it effectively:

for(TopLevel record: records) {
  for(ChildLevel childRecord: childRecords) {
    ...

This has a performance that approaches O(n2), which is the fifth slowest type of operation you can code (see Big-O notation). Anything slower than O(n log n) in Apex is likely to run into CPU governor limits, and you're doing so twice in your code.

Given 200 outer records and 200 inner records, you're going to match the inner loop about every 100 inner loop iterations on average. That means you're approaching 200,000 loop iterations in a list of 200 records (worst case scenario is 400,000).

It would be far more efficient if you could find a way to optimize this code to only run once by placing all this data into a map some sort. I'm not going to fix this for you, not entirely, but I'll get you started.

First, calculate all of the title values from the records:

Set<String> jobTitles = new Set<String>();
for(Contact c: newContactList) {
  jobTitles.add(c.Title?.toLowerCase());
}
jobTitles.remove(null); // Ignore null

Second, calculate the job titles into a map:

Map<String, String> titleToJobLevel = new Map<String, String>();
for(Update_Team__mdt cm : jobLevelMetaDataList) {
  String thisJobTitle;
  for(String jobTitle: jobTitles) {
    thisJobTitle = jobTitle;
    // Do your logic here for one title, put level into map per jobTitle
  }
  if(titleToJobLevel.get(thisJobTitle) != null) {
    jobTitles.remove(jobTitle); // Avoid future iterations for already calculated level
  }
}

Finally, assign those values:

for(Contact record: newContactList) {
  String jobLevel = titleToJobLevel.get(record.Title?.toLowerCase());
  ...

This should bring the algorithm much lower to O(n log n) from O(n2).

Also, you can make heavy use of the Safe Navigation Operator (?.) as demonstrated above to avoid many of your null checks.

1
  • Thanks.. I will do the changes as per your suggestions – Lanser Apr 22 at 13:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.