0

I am hitting SOQL Limits when I update a record from my custom object "OnBoarding_Data__c" . I have a trigger that is designed to create multiple "Case" records on before update. And as soon as the Case is created, I write the Id back to the main object - so it doesn't run again.

I look at the logs and it has many SOQL queries that are not part of my logic - but in "Case". It looks like other Flow / Process Builder / Trigger logic that executes SOQL when a Case record is created. See, creating 1 Case is not a problem, but creating 4 or 5 hits the limit.

I am wondering if there's another way of achieving this without worrying about the limits for creating Cases. Is using REST API an option? Would REST act as a separate execution thread for each case being built? I'm reading up on Async Apex - does anyone have experience with that?

Here is a sample of my code for reference:

trigger OnBoardingTrigger on OnBoarding_Data__c (before update) { 
    for(OnBoarding_Data__c onbd : Trigger.new){    
      if(onbd.Case1 != null){
           OnBoardingCase obc = new OnBoardingCase(onbd);
           obc.createCase1(onbd);           
      }
      /*****I have multiple of these if statements******/
   }
} 

Inside the class method: (I have multiple of these methods that do the almost the same thing)

public void createCase1(OnBoarding_Data__c onb) {
     Case cs = new Case();
     cs.Name = 'test'
     insert cs;     
     onb.Case1__c = cs.Id 
}

Any advice would be greatly appreciated.

2 Answers 2

2

There's not a generalized, magic-bullet solution, but there's at least one thing you can do in this trigger to try to avoid the problem. That's to bulkify your inserts. As you say, you have a series of if statements that call subsidiary methods in order to create Cases that you want to relate back to the trigger object. Right now, each of your subsidiary methods performs its own DML insert. It's possibly that collecting and bulkifying these inserts could help, although whether that's a successful approach will depend on exactly how your Case automation is consuming all of that SOQL.

One way to do this could be to create a Map<String, Case>, and pass it to each method. Each method creates a Case and puts it in the Map with its key being the name of the lookup field that its Id should populate, but doesn't insert it. Your example method would become

public void createCase1(OnBoarding_Data__c onb, Map<String, Case> caseMap) {
    // logic, do work ... then:
    caseMap.put('Case1__c', cs);
}

Then, when you're finished with all the subsidiary methods, you can do a single insert:

insert caseMap.values();

and iterate back over the map to populate the Ids into your lookup fields.

The "real", or underlying, problem appears to lie in your Case automation, whether that's a trigger, a large number of declarative automations like Flows, or a combination of the two. Hitting the SOQL limit after only 4-5 Case insert events is excessive and definitely needs to be addressed. It's possible you have some recursion issues causing automations to fire multiple times, which, in combination with multiple insert events, exceeds the limit quickly.

1
  • Thank you for the bulkify technique. Commented Feb 26, 2019 at 17:13
1

You are summoning a function with a dml operation inside a loop. That's what's causing you to reach the limit(because for each of those insert you trigger any other triggers you might have on Case).

You should create a data structure to store it and then realize just one DML operation outside the loop. This process is called Bulkify your code.

Here you can find more info about it: https://developer.salesforce.com/page/Best_Practice%3A_Bulkify_Your_Code

Example code:

 method() {
        for(){
          insert x;
        }
 }

Instead use this:

method() {
    List<Case> toInsert = new List<Case> ();   
    for(){
        toInsert.add(new Case(...));
     }
     insert toInsert;
}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .