3

As a Salesforce Apex developer, it is frequently desirable to have a QueryLocator instead of a List in order to overcome certain governor limits.

Moreover, for a variety of reasons, it can be preferable to use inline SOQL instead of dynamic SOQL to obtain the QueryLocator.

Usually if we use the [SELECT ...] syntax, we will get back a List.

But -- surprisingly -- if we do

for (Account account : [SELECT Id, ... FROM Account ...]) {
   // Whatever
}

or

Database.getQueryLocator([SELECT Id, ... FROM Account ...]);

Salesforce provides a QueryLocator instead of the List which might be expected.

Are there other contexts in which we can use this notation to get a QueryLocator?

5

Child relationships can return a QueryLocator. This can catch developers off-guard, because it requires relatively large amounts of data to happen. For example:

for(Account acc: [SELECT (SELECT Name FROM Contacts) FROM Account) {
  if(acc.Contacts.size() > 100) { // Do something
    ...

This code will work correctly if there are less than 200 contacts, but if there are more than that, the system may change acc.Contacts in to a QueryLocator. If this happens, an exception is thrown. You have to instead iterate over the values in a for loop:

for(Account acc: [SELECT (SELECT Name FROM Contacts) FROM Account) {
  Integer totalContacts = 0;
  for(Contact[] con: acc.Contacts) {
    totalContacts += con.size();
  }
  if(totalContacts > 100) { // Do something
    ...

This is a common trap that most developers do not account for in their code, which can can cause problems in some orgs.

Aside from that, there are no other special cases where a developer will directly get a QueryLocator out of an inline query.

There's an honorable mention, though. ApexPages.StandardSetController internally uses a QueryLocator to navigate between records when using a List View or inline query. You don't have direct access to it, however, which is why I don't consider it in the same category as the other three conditions.

  • Exactly what I wanted to know... I'll just leave the answer unaccepted for a bit to see if anyone else thinks of a scenario you didn't. :-) – Brian Kessler Jul 18 at 8:48
  • 1
    @BrianKessler I'd be just as interested in you in seeing such an answer. I'm pretty sure that's the complete list (your examples and mine), but I'd absolutely love to be proven wrong. I'd learn something new. – sfdcfox Jul 18 at 9:03
1

One honorable mention from me is SOQL For Loop that uses List instead of standard sObject.

    for(List<Account> accounts : [SELECT ID FROM Account]){
        for(Account acc : accounts){

        }
        System.debug(count);
    }

Quite useful if you wanna iterate over the large list but worried about heap. SOQL For Loop use can be bit tricky, the account.size() will always be 200, ie the governor engine does not actually know if we would be retrieving more than 50k rows, so it will allow you iterating till 50K records and then it would throw limits exception.

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.