The DataScroller itself knows NOTHING about how data are fetched. It just looks for the bound UIData component in tree (i.e. DataTable) and gets two values from the underlying instance of DataModel: datasetSize and getFirst() + pageSize from component. To 'know', which page is currently displayed, it calculates this from getFirst. To perform pagination, it calculates row index of first item at requested page and sets it to the DataModel with setFirst().

So, first of all we need to implement some derived from DataModel class, which handles our custom fetching method since all of UIData components (i.e. DataTable etc. and, indirectly DataScroller) are expecting an instance of such class as value. How to do this (and how to delegate the fetching of particular page of data to own MBean) is described in the Wiki. The advantage of this approach is that such DataModel don't need to hold ALL records in memory, but only the current page of data, which is currently displayed. But any way, we DO need to perform some kind of SELECT Count(*) at least once to know, how many records are available. Without to know this it's not possible to generate neither correct page list (1 2 3 4 5)  nor to decide, whether the "More" link sould be displayed. (You wish to display some kind of search results with 50 records per page - what if result dataset cosists of less than (5x50=)250 records but just of few or even 150 records? The scroller needs then to generate '<<1 2 3>>', not '<<1 2 3 4 5 More>>' :) )

It is exactly what the PagedListDataModel from Wiki does! It must to 'know' the total record count, to report it to DataScroller, so DataScroller cann generate the correct list of page numbers, but DataModel fetchs only the records, which should be currently rendered. Of course, it cann be extended to fetch more records at once (i.e. 250) and to store it internally in some kind of cache. One more reason to 'know' total record count (and probably, to preserve at least the list of record IDs after first query) is the sorting order. Let's say, we have 'found' only 100 records, the first page is rendered and the scroller looks like <<1 2>>. User clicks on '2', but the database has changed since page rendering - one record was inserted at first position. The last item from page 1 is then displayed as first on page 2 and the scroller looks like <<1 2 3>> I don't think, it's exactly what user expects from good designed GUI :)

In my case I'm doing no SELECT Count(*) but SELECT ID, hovever just once! That IDs are then stored in private ArrayList, so every time when the next portion is requested (i.e. one page of data must be rendered) I can get a corresponding sublist of IDs and fetch exactly this portion (i.e. with WHERE ID IN(...), what should be very fast if ID field is indexed in DB). In fact I don't have to care about "More", since EVERY page of data is fetched on demand. (If sorting order is not matter, we can rely on i.e. ROWNUM in Oracle or LIMIT in MySQL without to store initially any list but only the number or records, retrived with SELECT Count(*) or somehow else. Disadvantage in this case is, that we have then to perform SELECT with complete WHERE part (eventuely, with complex and time consuming conditions) for every page! Alternatively, we cann let EJB/Hybernate/whatever do the job, but any way it means, we will have large list of object instances in memory (eventually, extra session overhead too) or perform complex (and slow) querie for each page or portion of pages. To obtain some subset of data, the wohl set must be known => temporary stored in memory or defined by query conditions. I've found, that to store IDs in array of integer is the less possible overhead.

To implenemt "More" link, we need to extend the DataScroller, i.e. with new facet, which sould be rendered if at least one page more is available, and to know this, again, we need to know total record count (what about rendered="condition"? How should we define this condition, if total record count is unknown? :)  So, why not just let our extended scroller decide, whether facet should be rendered? ) May be, you cann use "fast step" of existing scroller... such click on "more" means nothing, but navigation to page 6 if possible (= [last displayed page number] + 1) and the fetching/cache works 'automaticly' in our DataModel.

The steps to implement own PagedListDataModel are exactly described in Wiki. The trick is to provide own derivat of DataModel, that 'looks' exactly like DataModel (it means, cann 'report', how many records it hase etc.) but every time, when getRowData() asks for record, which is not currently fetched (not in cache), it calls the fetchPage() method, which must be implemented in your MBean. You can get the code from Wiki 1:1. Just put the private class into your MBean and implement your fetchPage method, i.e.
public MyBean{
  ...
  private class LocalDataModel extends PagedListDataModel {
        public LocalDataModel(int pageSize) {
            super(pageSize);
        }
        
        public DataPage<MyItemClass> fetchPage(int startRow, int pageSize) {
            // call enclosing managed bean method to fetch the data
            return getDataPage(startRow, pageSize);
        }
  }
...
  private DataPage<MyItemClass> getDataPage(int startRow, int pageSize){
	
	List<MyItemClass> resultListOfObjects;
	//do your DB query here based on startRow and pageSize / your cache size.
	//put instances of MyItemClass into resultListOfObjects, i.e.

	while(?){
		resultListOfObjects.add(new MyItemClass(some data));
	}
	//totalRecordCount must be already known or retrived during this Q!

	return  new DataPage<MyItemClass>(totalRecordCount, startRow, resultListOfObjects);
  }
...
}

To keep this code reusable, it must be done this way in your MBean, because MyItemClass is the class, representing your data - you need to implement it somewhere, but it must be also 'known' because of type safety. I'm using this DataModel for many different result sets with different fetching behaviour, so I have my own interface/class hierarchy based on this approach. Any way, the implementation of cache (let's say, sized pageSize * 5 = 250 in your case) cann be done directly in PagedListDataModel. If you expect forward navigation only, your implementation cann just 'substitute' pageSize * 5 in call to fetchPage() method or you cann choose some smarter caching strategy.

Regards,
paul



[EMAIL PROTECTED] schrieb:
Hi Paul,
 
Thank you for your response.
But after going through this I have couple of questions on implementations.
Being pretty new jsf i am sorry if some of my doubts are irrelavent.
 
Since i want my GUI to look like  <<1 2 3 4 5 More >>.I need to implement a new facetn something like this while customizing <t:DataScroller>
<f:facet name="DBfetch">
<h:outputText value="More" rendered="condition"></h:outputText>
</f:facet>
 
Since Select COUNT(*) from DB is a time consuming operation.The client has ruled out this option.
So with the click of More i want to perform a database fetch in subsets of 250 records at a time.
I want to perform this operation in my page bean.
 
I want to know how can i link this getfetchData() method in my page bean with the <t:DataScroller>.
Is it possible.??
 
 
Best Regards,
Pallavi

From: Paul Iov [mailto:[EMAIL PROTECTED]]
Sent: Monday, February 19, 2007 6:48 PM
To: MyFaces Discussion
Subject: Re: Pagination of large database tables

Hi Pallavi!

First of all take a look at http://wiki.apache.org/myfaces/WorkingWithLargeTables. The illustrating code there is IMHO a little bit buggy (especially for subsets of large datasets, which commes from EJB it makes no sense to fetch the same page twice, since the sorting order never chahges), but generally this approach works fine.

I have exactly the same usecase - large resultsets and fetching on demand, but I'm using ac:AjaxDataScroller insteed of <t:dataScroller>, because the second one is not Ajax-compatible :( Any way, with own extended implementation of DataModel im background it would be preaty easy to implement "fetch more" feature, you are asking for.

regards,
paul

[EMAIL PROTECTED] schrieb:
Hi All,
 
I currently have a requirement for pagination.
I want the following GUI display <<1 2 3 4 5 more >>.
Where on click of << is for previous.
And on click of >> is for next.
So with these two i could go ahead with <t:dataScroller> for the above mentioned functionlity.
But if i had the advantage of knowing the total number of rows with DB to perform COUNT operation on the total number of rows.
 
But for larger tables this wouldn't be efficient.
Hence the requirement demands fetching rows in multiples of 250.
And each page displaying 50 rows per page.
With the click on more it would fetch the next 250 rows.
And the display should look like << 6 7 8 9 10 More >>.(something similar to google's pagination).
 
Is there a way by which i can implement this.
Or can i extend the functionality of <t:dataScroller> to implement this.
Any suggestions are welcome.
 
 
Best Regards,
Pallavi
 
 
 
 

The information contained in this electronic message and any attachments to this message are intended for the exclusive use of the addressee(s) and may contain proprietary, confidential or privileged information. If you are not the intended recipient, you should not disseminate, distribute or copy this e-mail. Please notify the sender immediately and destroy all copies of this message and any attachments.

WARNING: Computer viruses can be transmitted via email. The recipient should check this email and any attachments for the presence of viruses. The company accepts no liability for any damage caused by any virus transmitted by this email.

www.wipro.com


The information contained in this electronic message and any attachments to this message are intended for the exclusive use of the addressee(s) and may contain proprietary, confidential or privileged information. If you are not the intended recipient, you should not disseminate, distribute or copy this e-mail. Please notify the sender immediately and destroy all copies of this message and any attachments.

WARNING: Computer viruses can be transmitted via email. The recipient should check this email and any attachments for the presence of viruses. The company accepts no liability for any damage caused by any virus transmitted by this email.

www.wipro.com

Reply via email to