Salesforce Stack Exchange is a question and answer site for Salesforce administrators, implementation experts, developers and anybody in-between. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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?

share|improve this question
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 at 0:34
up vote 7 down vote accepted

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 );
    }
 }
share|improve this answer
2  
Great minds think alike :) – Boris Bachovski Mar 3 at 0:07
2  
and at same time !!! Phew ... – Mohith Shrivastava Mar 3 at 0:08
    
Thanks a lot Mohith and Boris for the solution. This worked perfectly. – Soudam Mar 3 at 5:44

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;
    }
}
share|improve this answer
1  
Great pattern !! – Mohith Shrivastava Mar 3 at 0:13
    
Thank you so much!! – Soudam Mar 3 at 5:46

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());
    }
}
share|improve this answer

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
 }
}
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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