9 Replies Latest reply on Oct 26, 2007 3:48 PM by griffitm

    DataTable Sorting Example

    griffitm

      Hello All,

      I have a seam-gen app that gives me a pretty good head start for the simple crud operations needed to maintain a database. I like the pagination of data that is baked in to the JSF pages as the data sources for the components are backed by the EntityQuery objects. However, I have a few instances where I need to build a custom query or do some Ajax look ahead type of querying, and I'd like my datatables in those lists to look and feel like the datatables that are bound to the EntityQuerys. The nice thing about the EntityQuery is that you get the pagination and ability to resort the data simply. Can I use this in my Stateful session bean instead of using EntityManager.createQuery()?

      Does anyone know of an example where the data for the JSF page is coming from a session bean page controller and has the ability to sort/paginate data easily?

      Thanks in advance!

      Cheers!
      mg

        • 1. Re: DataTable Sorting Example
          pmuir

          I'm not really following your question, so you might want to try to ask it slower ;)

          You know you can extend EntityQuery programatically and add whatever you like to it?

          • 2. Re: DataTable Sorting Example
            griffitm

            Pete,

            Thanks for the reply. I can have a stateful session bean that extends EntityQuery? I guess I didn't think of that. What I ended up doing was using EntityQuery to perform my query, and exposing the methods from EntityQuery that are used by the JSF pages for sort/filtering. It mostly works. The list appears, with the pagination, but when I go to the 2nd page then go back to the first page, the pagination links disappear. The expression I'm using for rendered always returns false. Its something like:

            
            From the view...
            <s:link view="DeliverableSearch.xhtml" rendered="#{deliverableSearch.previousExists} .../>
            
            From the Stateful session bean...
            DeliverableSearch.java
            ...
            public boolean getPreviousExists(){
             return enitiyQuery.isPreviousExists(); // internal instance var for query
            }


            Maybe isPreviousExists doesn't do what I think it does.

            • 3. Re: DataTable Sorting Example
              pmuir

               

              "griffitm" wrote:
              Thanks for the reply. I can have a stateful session bean that extends EntityQuery?


              You couldn't up until AS 4.2.2 due to some bugs in JBoss' EJB3 implementation, and I haven't checked since it was released earlier this week.

              Whatever, you can have a Seam JavaBean component that extends EntityQuery (which is all EntityQuery is).

              That code looks right, but EntityQuery is quite a tricky component to get all the refreshing right for.

              • 4. Re: DataTable Sorting Example
                griffitm

                Pete,

                I thought of doing this as a declared query, in components.xml -- but the search is a on a date range of a field on the entity bean. All of the examples I've seen use the instance of the entity to back the search form, and to submit the form values for the query -- Unless you use a session bean. Is there a way I can declare the query in my components.xml file like:

                select d from Deliverable d where d.dueDate > :parm1 and d.dueDate < :parm2
                


                Then bind the parameters from a search form?

                Thanks in advance,

                MG

                • 5. Re: DataTable Sorting Example
                  pmuir

                  Any valid hql/ejbql can be used in restrictions.

                  so

                  <framework:entity-query name="q" ejbql="select d from Deliverable d">
                   <framework:restrictions>
                   <value>d.dueDate &gt; #{date1}</value>
                   <value>d.dueDate &lt; #{date2}</value>
                  ...


                  should work (assuming your statement above is valid ejbql).

                  But you can also do

                  @Name("q")
                  public class QQuery extends EntityQuery {
                   // implement getRestrictions and getEjbql


                  for a more extensible system (n.b. it's NOT a session bean)

                  • 6. Re: DataTable Sorting Example
                    griffitm

                    Ok, I tried restructuring this as a framework query, and the query works, but the pagination throws an exception.

                    First the query as defined in components.xml:

                    <framework:entity-query name="deliverableSearchList"
                     entity-manager="#{em}"
                     ejbql="select d from Deliverable d"
                     order="d.dueDate">
                     <framework:restrictions>
                     <value>d.dueDate > #{search.fromDate}</value>
                     <value>d.dueDate < #{search.toDate}</value>
                     </framework:restrictions>
                     </framework:entity-query>
                    


                    And My XHTML:
                    <!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
                     "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
                    
                    <ui:composition xmlns="http://www.w3.org/1999/xhtml"
                     xmlns:s="http://jboss.com/products/seam/taglib"
                     xmlns:ui="http://java.sun.com/jsf/facelets"
                     xmlns:f="http://java.sun.com/jsf/core"
                     xmlns:h="http://java.sun.com/jsf/html"
                     xmlns:rich="http://richfaces.org/rich"
                     template="layout/template.xhtml">
                    
                    <ui:define name="body">
                    
                     <h:messages globalOnly="true" styleClass="message" id="globalMessages"/>
                    
                     <h:form id="searchCriteria" styleClass="edit">
                    
                     <fieldset>
                     <rich:simpleTogglePanel label="Deliverable Date Search" switchType="ajax">
                    
                     <s:decorate template="layout/display.xhtml">
                     <ui:define name="label">From Due Date:</ui:define>
                     <rich:calendar id="fromDueDate" popup="true" enableManualInput="true"
                     value="#{search.fromDate}" pattern="MM/dd/yyyy"
                     event="onclick" reRender="completionDateDecoration" bypassUpdates="true"/>
                    
                     </s:decorate>
                    
                     <s:decorate template="layout/display.xhtml">
                     <ui:define name="label">To Due Date:</ui:define>
                     <rich:calendar id="toDueDate" popup="true" enableManualInput="true"
                     value="#{search.toDate}" pattern="MM/dd/yyyy"
                     event="onclick" reRender="completionDateDecoration" bypassUpdates="true"/>
                     </s:decorate>
                    
                     </rich:simpleTogglePanel>
                    
                     <div class="actionButtons">
                     <h:commandButton id="search" value="Search" action="/Search.xhtml"/>
                     </div>
                     </fieldset>
                     </h:form>
                    
                    
                     <rich:panel>
                     <f:facet name="header">Deliverable Search Results</f:facet>
                     <div class="results" id="deliverableSearchList">
                    
                     <h:outputText value="No deliverable exists"
                     rendered="#{empty deliverableSearchList.resultList}"/>
                    
                     <rich:dataTable id="deliverableSearchList"
                     var="deliverable"
                     value="#{deliverableSearchList.resultList}"
                     rendered="#{not empty deliverableSearchList.resultList}">
                     <h:column>
                     <f:facet name="header">
                     <s:link styleClass="columnHeader"
                     value="Deliverable #{deliverableSearchList.order=='description asc' ? messages.down : ( deliverableSearchList.order=='description desc' ? messages.up : '' )}">
                     <f:param name="order" value="#{deliverableSearchList.order=='description asc' ? 'description desc' : 'description asc'}"/>
                     </s:link>
                     </f:facet>
                     #{deliverable.description}
                     </h:column>
                     <h:column>
                     <f:facet name="header">
                     <s:link styleClass="columnHeader"
                     value="Due Date #{deliverableSearchList.order=='dueDate asc' ? messages.down : ( deliverableSearchList.order=='dueDate desc' ? messages.up : '' )}">
                     <f:param name="order" value="#{deliverableSearchList.order=='dueDate asc' ? 'dueDate desc' : 'dueDate asc'}"/>
                     </s:link>
                     </f:facet>
                     #{deliverable.dueDate}
                     </h:column>
                     </rich:dataTable>
                    
                     </div>
                     </rich:panel>
                    
                     <div class="tableControl">
                    
                     <s:link view="/Search.xhtml"
                     rendered="#{deliverableSearchList.previousExists}"
                     value="#{messages.left}#{messages.left} First Page"
                     id="firstPage">
                     <f:param name="firstResult" value="0"/>
                     </s:link>
                    
                     <s:link view="/Search.xhtml"
                     rendered="#{deliverableSearchList.previousExists}"
                     value="#{messages.left} Previous Page"
                     id="previousPage">
                     <f:param name="firstResult"
                     value="#{deliverableSearchList.previousFirstResult}"/>
                     </s:link>
                    
                     <s:link view="/Search.xhtml"
                     rendered="#{deliverableSearchList.nextExists}"
                     value="Next Page #{messages.right}"
                     id="nextPage">
                     <f:param name="firstResult"
                     value="#{deliverableSearchList.nextFirstResult}"/>
                     </s:link>
                    
                     <s:link view="/Search.xhtml"
                     rendered="#{deliverableSearchList.nextExists}"
                     value="Last Page #{messages.right}#{messages.right}"
                     id="lastPage">
                     <f:param name="firstResult"
                     value="#{deliverableSearchList.lastFirstResult}"/>
                     </s:link>
                    
                     </div>
                    
                    
                     <s:div styleClass="actionButtons" rendered="#{empty from}">
                     <s:button view="/DeliverableEdit.xhtml"
                     id="create"
                     value="Create Deliverable">
                     <f:param name="deliverableId"/>
                     </s:button>
                     </s:div>
                    
                    </ui:define>
                    
                    </ui:composition>
                    

                    And my managed Bean:
                    @Name("search")
                    @Scope(ScopeType.SESSION)
                    public class Search {
                    
                     /** Creates a new instance of Search */
                     public Search() {
                    
                     }
                     private Date fromDate;
                     private Date toDate;
                    
                     public Date getFromDate() {
                     if(fromDate == null){
                     fromDate= Calendar.getInstance().getTime();
                     }
                     return fromDate;
                     }
                    
                     public void setFromDate(Date fromDate) {
                     this.fromDate = fromDate;
                     }
                    
                     public Date getToDate() {
                     if(toDate == null){
                     Calendar calendar= Calendar.getInstance();
                     calendar.roll(Calendar.DAY_OF_YEAR, 30);
                     toDate= calendar.getTime();
                     }
                     return toDate;
                     }
                    
                     public void setToDate(Date toDate) {
                     this.toDate = toDate;
                     }
                    
                    
                    }
                    


                    Throws Exception:
                    javax.faces.FacesException: javax.el.ELException: /Search.xhtml @162,33 rendered="#{deliverableSearchList.nextExists}":
                    Error reading 'nextExists' on type org.jboss.seam.framework.EntityQuery_$$_javassist_9
                     at javax.faces.component.UIComponentBase.isRendered(UIComponentBase.java:373)
                     at javax.faces.component.UIComponent.encodeAll(UIComponent.java:880)
                    


                    If I remove the pagination, the search works fine. How is this any different from the managed components generated by seam gen?
                    Any help would be much appreciated!

                    Best Regards,
                    MG

                    • 7. Re: DataTable Sorting Example
                      pmuir

                      Whole exception?

                      • 8. Re: DataTable Sorting Example
                        griffitm

                        The root cause of the exception was null pointer in isNextExists(); The error seems to be related to getMaxResults() returning a null if no resultset has been defined.

                        Adding max-results=25 to the framework query fixed the error, but it seems like the error should be caught in getMaxResults and handled there.

                        The unfortunate thing is that this implementation suffers from the same problem that my original implementation does. The list appears, you can click on next page to navigate to the next page, click on previous page to return to the first page and the pagination disappears.

                        MG

                        • 9. Re: DataTable Sorting Example
                          griffitm

                          Update to my problem: Adding action="pageControllerBean.action" fixed the pagination problem.

                          This is strange, maybe a bug? The initial result set that I was trying to paginate was being managed by a stateful session bean that encapsulated an EntityQuery object. I had some logging code in the search() method of my bean to display the query parameters, and everything looked as I suspected -- however I could not get my page to sort or paginate correctly until I added the attribute action to the link.

                          So my source went from:

                          <s:link view="/DeliverableSearch.xhtml"
                           rendered="#{deliverableSearch.previousExists}"
                           value="#{messages.left}#{messages.left} First Page"
                           id="firstPage">
                           <f:param name="firstResult" value="0"/>
                           </s:link>

                          To:
                           <s:link view="/DeliverableSearch.xhtml" action="#{deliverableSearch.search}"
                           rendered="#{deliverableSearch.previousExists}"
                           value="#{messages.left}#{messages.left} First Page"
                           id="firstPage">
                           <f:param name="firstResult" value="0"/>
                           </s:link>


                          I added the same action attribute to the link that sorted the data as well. This fixed both the pagination and sorting issue. The question is, why was the page not performing as expected before, when clearly I know the search method on the bean was being called because I could see the output in the log file...

                          Best Regards,


                          MG