+ Start a Discussion
DevGarethmdDevGarethmd 

VisualForce Pagination Limitations

I've been able to get the pagination to work with a custom controller, however there seem to be some limitations that restrict its use that i wanted to check to make sure that i am correct.

Firstly, pagination only works if you instantiate the setController from a query locator using Database.getQueryLocator. If you instantiate using a list of sObjects then the pagination is ignored and the whole recordset is returned. This is kind of a shame as the getQueryLocator does not accept dynamic SOQL, so if you want to build a fairly sophisticated search facility with paginated results then it does not appear to be possible using this method.

Secondly, you are also not able to use lists of wrapper classes that contain results sets. For example if you wanted to allow the user to select multiple records from a search result my understanding is that the only way to do this is to construct a wrapper class that contains both the sobject and a boolean field to indicate whether the record has been selected. Since a StandardSetController can only be instantiated using Sobjects, pagination again does not appear possible.

Can anyone confirm if my understanding is correct and if it is, then how would i go about developing a paginated solution for these scenarios?

Thanks
Gareth
Best Answer chosen by Admin (Salesforce Developers) 
mtbclimbermtbclimber

Yes, dynamic SOQL has been supported now for sometime.   You still need to utilize the querylocator but you can now get one with dynamic soql.

All Answers

mtbclimbermtbclimber
StandardSetControllers do not support dynamic SOQL yet. This is a known limitation. The collection-based constructor is really meant to be used in apex test methods where you need the result to be predictable. Giving it a collection of 10k records offers no real optimizations. Your only real solution there is to utilize the "first" attribute on the iteration components to show only the rows of interest but you are going to have to pull the entire set into your request (or at least 1 more than the last row you are showing in the current page)

You can, however, leverage the standardsetcontroller with wrapper classes though you need to control the construction of the wrapper collection from getRecords on the standardsetcontroller yourself. There is another thread which has more information on this approach:

http://community.salesforce.com/sforce/board/message?board.id=Visualforce&message.id=5970
crop1645crop1645

First of all, thanks to Gareth and Andrew for this.

 

1.  I can confirm (after 6 hours of experimentation before I read Gareth's post) that pagination will only work with the Database.getQueryLocator constructor for the StandardSetController.  In retrospect, this should be obvious as the whole point of the pagination is to do on-demand database queries as the user does next, next, ...  If you use the collection-based constructor for the StandardSetController, all the records have already been fetched so pagination from an optimization of DB query point of view can't happen.  Nevertheless, you might be tempted (as was I) to use the collection-based constructor thinking it would be easy to get next, previous, first, last functions for free. 

 

Put another way, let's say you know that you'll only retrieve at most 200 records in your record set.  For screen real-estate reasons, you want to have a page size of 10 and let the user page through 1,2,3...20 pages.  Maybe you know that your query sorts the most 'interesting/relevant' result objects first.  You think, executing a 200 result row query is pretty fast, so you use the collection-based constructor because, quite frankly you use collections (Lists, Sets) all the time in triggers and what have you.

 

And, you think the SFDC guys are clever enough to make getRecords obey whatever pageSize you established on your StandardSetController -- after all, why should those functions care how the object was initialized? They should be indifferent.

 

Well, you think wrong.  You want pagination, you have to use the Database.getQueryLocator constructor.

 

2.  Furthermore, if you use the collection-based constructor for the StandardSetController, and then code something like this:

someSetController.setPageSize(10);

 results are unpredictable as of Spring 09 March 27, 2009.  For example, in some tests I did, the debug statement immediately following the setPageSize(nn) method call never executed and the controller just stopped without an exception:

someSetController.setPageSize(10);
System.debug('**I just changed the pageSize');

 My suggestion for SFDC product management is to improve the Spring09 documentation as follows:

 

VF Developers Guide: StandardSetController class documentation on page 132 -- if using the list of sObjects constructor:

  • Pagination feature not available
  • Method getRecords() will always return the entire list of sObjects, regardless of pageSize
  • Method setpageSize() should not be used - results are undefined.


APEX Developers Guide: Database.getQueryLocator and QueryLocator object

  • Although there are examples given on how to use this method and object, including in a StandardSetController, it is not well-defined exactly what is a QueryLocator.  Put another way, it is not explained as well as List, Set, or Map objects and corresponding methods 

 

 

 

 

Message Edited by crop1645 on 03-27-2009 04:51 PM
guest1231231guest1231231

Is there any update on this topic?

mtbclimbermtbclimber

Yes, dynamic SOQL has been supported now for sometime.   You still need to utilize the querylocator but you can now get one with dynamic soql.

This was selected as the best answer
guest1231231guest1231231

Thanks mtbclimber,

 

Is it possible to have pagination for a subquery?

 

http://community.salesforce.com/t5/Visualforce-Development/Rendering-Child-Object-From-List-Controller/td-p/203559

 

Thanks