function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
asadimasadim 

What is a QueryLocator?!

Hi,

 

I cannot find anything neither in the documentation nor on the web that answers my question. It is used throughout the batch Apex guide yet there's no formal definition for it. What kind of object is it? What can I do with it?

 

Also how do you access the children retrieved using a QueryLocator like so (it's a relationship query):

 

Database.getQuerylocator([select Id, Name, (select Name from Account) from Contact]);

 

Thanks in advance.

 

aalbertaalbert

Here is a link to the short doc on QueryLocator object.

 

The children records can be accessed in the execute method of Batch Apex. For example:

global void execute(database.BatchableContext ctx, SObject[] scope){ new Map<String,Integer>(); for(sobject s : scope){ Account a = (Account)s; List<Contact> contacts = a.Contacts; //accessing children records here }

 

Or in your case, you need to update your SOQL statement to something like:

 

[select Id, FirstName, Account.Name from Contact] to reference the parent Account.Name value. 

asadimasadim

Thanks aalbert but I'd seen that writeup already and that doesn't answer what a QueryLocator is.

 

With regards to accessing children of a parent, I should've used custom objects in my example because that's the actual problem. Like so:

 

 

select Name, (select Name from Childs__r) from Parent__c

 

What would be the equivalent of a.Contacts (from your code) in this case? I've tried a.Childs__r and a.Child__c and none have worked. I don't think using a.get('Child__c') would work in this case either. Any ideas?

 

EDIT: The second issue is fixed. I had to cast the sObject to my object type inside execute() and then call Childs__r on it.

Message Edited by asadim on 10-29-2009 02:48 PM
aalbertaalbert

More info on a QueryLocator in the API docs here.

 

I recommend using the force.com ide 'schema explorer' to get a list of child relationships. Open up the Force.com Ide project, double-click on the 'salesforce.schema' icon, and expand out the proper object in the right hand panel. Expand out the Child Relationships to see a list of relationship names (which is configurable).

 

 

TehNrdTehNrd

I would have to agree that there is a decent amount of confusion on what exactly a queryLocator is, when, and why it should be used over regular SOQL.

A blog post or article written by someone at salesforce.com on this topic would be incredibly useful.

I have attempted to figure some of this out on my own but it is still confusing:
http://community.salesforce.com/sforce/board/message?board.id=apex&thread.id=21858

Message Edited by TehNrd on 10-29-2009 04:14 PM
aalbertaalbert

I am aware of two places that its relevant:

(a) SOQL query in the web services API: When you query a large set of data, not all of that dataset is returned in the initial response, so internally salesforce.com uses the querylocator to reference the entire dataset on the server side. So the initial query response returned the first 2000 rows, the queryLocators is aware to return rows 2001-4000 on the corresponding QueryMore() call , and so on. Its just a server side cursor or pointer to the next set of data to return in the queryMore call.

 

(b) Batch Apex: When batch apex is invoked with the start() method, you are creating a queryLocator on the server-side. Then internally, the system chunks it up into corresponding batches to pass it into the execute() method. But as the developer, just consider the start() method as defining the dataset which happens to be of datatype QueryLocator. 

 

Does that help?

 

 

TehNrdTehNrd

Yup, I knew that you must use a queryLocator for batch apex but it also seems like there are some other advanatages such as the one list in my post above.

I did a quick scan through the apex docs and it seems, in regard to Apex, these are the only two things it is good for:
1) Batch Apex

2) Initializing standardSetControllers with up to 10,000 records.

For some reason I was thinking (maybe hoping) it had more magical powers.

asadimasadim

aalbert, I'd seen your other link too but not much help there either. You see, the page talks about this "cursor" thing that the QueryLocator is supposed to provide but how would I even use this cursor? Not that I need it but pointing out the lack of proper documentation. I still don't know what a QueryLocator is.

Message Edited by asadim on 10-29-2009 04:48 PM
richardvrichardv

The following code will run successfully; however, this is all I'm aware you can do.  Anyone know of any other available methods?

 

Database.QueryLocator ql = Database.getQueryLocator([SELECT Id FROM Account]);

System.debug(ql);
System.debug(ql.getQuery());

 

And has log output of following:

 

09:02:21 INFO - 20091203150224.586:AnonymousBlock.al: line 1, column 28: SOQL locator query with 12 rows finished in 40 ms
20091203150224.586:AnonymousBlock.al: line 2, column 1: Database.QueryLocator[Query=SELECT Id FROM Account]
20091203150224.586:AnonymousBlock.al: line 3, column 1: SELECT Id FROM Account