views:

345

answers:

1

UPDATE II: OK, I managed to narrow it down a little.

I have a page with a datatable with sorting and filtering functionalities, both taking place in the DB. In other words, I do not use the embedded functionality of the rich:datatable I use, but rather let the DB do the work.

I work with request-scoped beans. The only session-scoped beans contain the sorting and filtering of my interface.

Filtering for each column is bound to the certain session bean fields. As such, it is actually updated during the Update Model Values phase.

Sorting required some logic from my part, so I invoke a certain method to set the correct values to the session bean. This is performed during the Invoke Application phase.

So, any changes are in place during the Render Response phase, where the page actually renders.

The problem is that the JSF datatable and datascroller in my page call the backingBean.getDataModel() that fetch the data from the DB and the dataModel.getRowCount() (which I have implemented to invoke a method that runs a separate query) also during the Apply Request Values phase. These two queries take also place during the Render Response Phase, which is the only phase where the changes are all in place, and the query will run normally.

This means that to show a page after I perform filtering or sorting, the double number of queries take place.

I want to perform sorting and filtering only performing the required queries and no more.

Any suggestions?

+1  A: 

The getter call during apply request values phase is mandatory because JSF needs to know which input values were initially shown so that it can eventually do any validation and/or call any valuechangelisteners in the next phase where applicable. It is also mandatory to find out which button/link was pressed/clicked in any of the rows so that it knows which bean action to call in the invoke action phase.

But if you don't have any input fields which are to be validated/valuechange-checked nor any buttons/links in any of the rows, then I can imagine that the query during apply request values phase is in your eye completely superfluous.

Unfortunately, you can't completely disable it. Technically, the only resort to that is putting the data bean in the session scope and do the expensive SQL query (and refresh of datamodel) only in the constructor of the bean and in the bean action method, so that it only get invoked during bean's construction (for 1st view) and during bean's action method (during a new sort/filter/whatever request). The disadvantage is however that any changes in the datamodel are reflected in all windows/tabs the enduser has open in the same session, which might cause "wtf?" experiences for the enduser.

Now, Tomahawk was the first which has a nice workaround for this in flavor of the preserveDataModel attribute for the <t:dataTable>, which basically puts the datamodel in the request-specific component tree (which in turn is already stored in the session scope or in a hidden input field in the client side, depending on how you configured the store location of the view state in faces-config). RichFaces doesn't have a direct solution like that, but the <a4j:keepAlive> does basically the same. It would only affect the "whole" bean, thus if your data bean contains more than only the datamodel, you might consider to refactor it. You should keep in mind to design the bean as if it is a session scoped bean.

If the datamodel gets large, then I can imagine that this impacts the server memory, but this shouldn't really harm that much if you only stores the viewable part of the datamodel in memory (and thus not the entire datamodel, including all the other pages). See if it outweighs the cost of firing double SQL queries during a single HTTP request.

Hope this helps.

BalusC
Since I am using RichFaces I have considered a4j:keepalive. In addition to the fact that data needs to be written in session, I also read that it may be responsible for memory leaks. Is there any other way to have the changed data available before the Apply Value Changes phase? f:param, f:setPropertyChangeListener both call the setters in Update Model Values? What about setting the changed data as request parameters? Or GET params? Is any of that feasible?
Markos Fragkakis
Wrt memory leaks: it would then be a bug in the tag which needs to be reported to and fixed by JBoss guys. Wrt request parameters: it's not only about the updated datamodel, but also the **initial** datamodel, i.e. the one which was displayed to the client at the moment the client takes actions. This information isn't available by request parameters. Only the updated information is available by request parameters. I am also silently ranting on this "nature" of JSF, but I'm happy enough with Tomahawk `t:saveState` which I use for the complete bean incl. datamodel and paging/sorting attributes.
BalusC
(I can only put 600 chars in a comment, so here's one more) If you're interested, you can find an example in one of my blogs: http://balusc.blogspot.com/2008/10/effective-datatable-paging-and-sorting.html True, you'll miss the RichFaces look'n'feel, but OK, first see if it helps to grab `a4j:keepAlive` before dropping the datascroller and homegrow a bunch of buttons and logic as described at the aforementioned blog. Good luck.
BalusC
Thanks man, this helps.
Markos Fragkakis