|
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:
|

