7

I need to query Queue Ids in the before and after triggers on the same object, using the same SOQL statements. As hard coding them is not a good practice, I want to check if there is any way to avoid repetition to reduce the number of queries. Can I use global/static variables to hold these queried Ids?

  • 1
    I think all the answers below are similar. They all aim to have a static variable held somewhere so you only have to query the database once. I've generally used the lazy load approach in the past because it works from anywhere. It doesn't matter what code calls it, or where it calls it from, it will always work. – Nick Cook Mar 3 '16 at 0:34
8

Yes static variables are meant for same purpose .

Create a static list in your helper class and use same in your before trigger and after trigger

public class cachequery { 
  public static List<Account> lstaccount= [Select Id,Name from Account LIMIT 10]; 
}

The sample trigger to provide an idea

trigger T1 on Account (before insert, after insert) { 
  list<Account> lstcached = cachequery.lstaccount;
   if(Trigger.isBefore && Trigger.isInsert){
      system.debug(lstcached );
    }
   if(Trigger.isAfter && Trigger.isInsert){
      system.debug(lstcached );
    }
 }
| improve this answer | |
  • 2
    Great minds think alike :) – Boris Bachovski Mar 3 '16 at 0:07
  • 2
    and at same time !!! Phew ... – Mohith Shrivastava Mar 3 '16 at 0:08
  • Thanks a lot Mohith and Boris for the solution. This worked perfectly. – Kanikala Mar 3 '16 at 5:44
8

This is a good time to learn about the Lazy Load pattern. You can write your cache in such a way that you only consume the query if you actually need the data. Now if you make a reference to this Apex Class to perform some logic that has no need for the query, you will not touch your governor limits.

public with sharing class MyService
{
    public static List<Group> cachedQueues
    {
        get
        {
            if (cachedQueues == null)
            {
                cachedQueues = [/*query*/];
            }
            return cachedQueues;
        }
        private set;
    }
}
| improve this answer | |
4

You can do that by storing the results into a static variable outside the trigger - perhaps in your trigger handler class.

For an example we have a trigger on Account and we want to store a list of Contacts for our before and after execution (instead of querying twice):

Trigger Handler:

public with sharing class TriggerHandler
{
    public static List <Contact> contacts;
}

Then in your trigger you can set the list of contacts in the before execution, which then will be also available in the after execution. Both run in the same transaction and the static variables are available throughout the whole transaction - it's the same context.

trigger AccountTest on Account (before insert, after insert)
{
    if (trigger.isBefore)
    {
        TriggerHandler.contacts = [SELECT Id FROM Contact];
    }
    else
    {
        system.debug(TriggerHandler.contacts.size());
    }
}
| improve this answer | |
2

I'll go one more on @AdrianLarson answer. The lazy load approach, which makes plenty of sense to minimize SOQLs until needed can sometimes run into trouble in test classes where your mocking of sobjects executes triggers/handlers which populate the cache and then, if you then mock a cacheable sobject (like mock a new Queue), the new sobject won't get in the cache and your testmethod may fail on an assert.

Now obviously you can try to sequence your mocks so that anything that would go into a cache is mocked first before the cache is lazily built but sometimes, this is not practical, so the dirtyCache() method allows the cache to be rebuilt.

public with sharing class MyService {
 public static List<Group> cachedQueues {
    get {
        if (cachedQueues == null)
            cachedQueues = [/*query*/];
        return cachedQueues;
    }
    private set;
 }
 public static void dirtyCaches() {
      cachedQueues == null;
      cacheXXX = null; // other caches to dirty
 }
}
| improve this answer | |

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.