12 Replies Latest reply on Feb 4, 2009 11:42 AM by jalal.din

    Problem with ExtendedDataModel and rich:datascroller

    hristo

      Hi,
      I've read a lot of posts regarding pagination and rich:datascroller but I still can't solve one problem.
      I'm trying to make a real pagination in the database by querying for just the number of results that I need. Otherwise rich:datascroller returns the whole result set and then only shows a small part of it which does not work well for large result sets.
      My problem is that I cannot set my datascroller to show the correct number of pages using an ExtendedDataModel. The reason for this is that ListSequenceDataModel is used for calculating the number of pages instead of my ExtendedDataModel. This looks more like a bug in Richfaces DataScroller but I'm not sure.
      Here is the details:
      I have TestDataModel class which extends SerializableDataModel where in wrappedData I return just 10 elements but my getRowCount method returns the number of all records in the database which is 500. The datascroller though shows that there is only one page.
      I debug the richfaces code to see how the datascroller is rendered.
      This is done mainly in DatascrollerTemplate and DataScrollerRenderer in package org.richfaces.renderkit.html. As expected the datascroller uses the DataModel of the DataTable to calculate the number of pages:
      org.richfaces.component.UIDatascroller.getRowCount(UIData data)
      and after:
      UIDataAdapter.getRowCount(){
      ... return getExtendedDataModel().getRowCount();
      }

      Here getExtendedDataModel() returns an instance of ModifiableModel which field "originalModel" contains my custom TestDataModel. So modifiableModel.getOriginalModel.getRowCount will return 500 as I need. But look at the implementation of modifiableModel.getRowCount:

      public int getRowCount() {
      return delegate.getRowCount();
      }

      !!!???
      delegate is an instance of ListSequenceDataModel which contains the list wrappedKeys. So getRowCount() returns wrappedKeys.size() which is 10 so the datascroller renders with only one page.

      At the time of rendering the dataTable when the model is created () both fields: originalModel and delegate are set to TestDataModel. But at some point before delegate is set to ListSequenceDataModel and returns the size of the list.

      Here is an example of my code:

      @Name("testDataModel")
      @Scope(ScopeType.SESSION)
      public class TestDataModel extends SerializableDataModel {
      
       private Integer currentPk;
      
       private boolean detached = false;
       private List<Integer> wrappedKeys = null;
       private final Map<Integer, User> wrappedData = new HashMap<Integer, User>();
       private Integer rowCount;
      
       @In(create = true)
       private UserService userManager;
      
       @Override
       public void walk(FacesContext context, DataVisitor visitor, Range range, Object argument) throws IOException {
       if (detached){
       for (Integer key : wrappedKeys) {
       setRowKey(key);
       visitor.process(context, key, argument);
       }
       } else {
       int firstRow = ((SequenceRange) range).getFirstRow();
       int numberOfRows =((SequenceRange) range).getRows();
       wrappedKeys = new ArrayList<Integer>();
       for (User user : userManager.findUsersPaged(firstRow, numberOfRows, null, null)) {
       wrappedKeys.add(user.getId());
       wrappedData.put(user.getId(), user);
       visitor.process(context, user.getId(), argument);
       }
       }
       }
      
      ...
       @Override
       public int getRowCount() {
       rowCount = userManager.countUsers();
       return rowCount;
       }

      This is my seam managed component:
      @Scope(ScopeType.SESSION)
      @Name("userManager")
      public class UserAction implements UserService{
      ...
       public List<User> findUsersPaged(int firstRow, int numberOfRows, String sortField, boolean descending) {
       List<User> users = entityManager.createQuery("select u from User u").setFirstResult(firstRow).setMaxResults(numberOfRows).getResultList();
       return users;
       }


      Another thing is that there is no way to set the number of pages directly to the UIDatascroller component either by an attribute or by the API
      I'm very interested to see how this problem can be solved.
      If anyone is familiar with this could you give me a tip.

      Many thanks,
      Hristo

        • 1. Re: Problem with ExtendedDataModel and rich:datascroller
          nbelaevski

          Hristo,

          Can you please try 3.2.2.BETAx?

          • 2. Re: Problem with ExtendedDataModel and rich:datascroller
            hristo

            Thanks for the suggestion. I tried it with 3.2.2.BETA5, but it's still the same.

            • 3. Re: Problem with ExtendedDataModel and rich:datascroller
              nbelaevski

              Well, can you please create a small example and attach it to a new JIRA issue? Thank you in advance!

              • 4. Re: Problem with ExtendedDataModel and rich:datascroller
                konstantin.mishin

                Post your page source, please.

                • 5. Re: Problem with ExtendedDataModel and rich:datascroller
                  hristo

                  I've created a new JIRA issue:
                  https://jira.jboss.org/jira/browse/RF-4283

                  I've attached an example code including the page source but here it is again:

                  <rich:dataTable id="containerList" rows="10" var="c" value="#{testDataModel}">

                  <rich:column>
                  <f:facet name="header">
                  <h:outputText value="Name" />
                  </f:facet>
                  <h:outputText value="#{c.name}" />
                  </rich:column>
                  </rich:dataTable>
                  <rich:datascroller align="left" for="containerList" maxPages="10" rendered="true" />

                  As you see the example code is as simple as possible

                  • 6. Re: Problem with ExtendedDataModel and rich:datascroller
                    konstantin.mishin

                    This problem is reproduced with versions older 3.2.2.BETA5. But I cannot reproduce with this version. Can you please attach war, where problem is reproduced with 3.2.2.BETA5.

                    • 7. Re: Problem with ExtendedDataModel and rich:datascroller
                      nbelaevski

                       

                      "konstantin.mishin" wrote:
                      This problem is reproduced with versions older 3.2.2.BETA5. But I cannot reproduce with this version. Can you please attach war, where problem is reproduced with 3.2.2.BETA5.


                      I guees you meant 3.2.2.BETAs 1 to 5?

                      • 8. Re: Problem with ExtendedDataModel and rich:datascroller
                        hristo

                        Hi,
                        Thank you for your interest on my problem.
                        This issue certainly exists in version 3.2.2.BETA5

                        The main class concerned is
                        org.richfaces.model.ModifiableModel

                        Konstantin, I see that you are the author of this class so you are familiar with it.

                        Two methods are interesting for me here:
                        1) getRowCount()
                        2)modify(List, List<SortField2>)

                        When rich:datascroller is being rendered it uses the first method to calculate the number of pages. If I have 500 records in the database and I show 10 records per page then I need to have 50 pages.
                        The method walk(FacesContext , DataVisitor , Range ,Object ) will return 10 records from the database which I will display but getRowCount() must return 500 which is the total number of records. This way the datascroller will render with 50 pages.

                        The implementation of ModifiableModel.getRowCount() is:

                        public int getRowCount() {
                         if (rowKeys == null) {
                         return -1;
                         } else {
                         return rowKeys.size();
                         }
                         }


                        rowKeys is set in modify(...) :
                        public void modify(List<FilterField> filterFields, List<SortField2> sortFields) {
                         int rowCount = originalModel.getRowCount();
                        ...
                        rowKeys = new ArrayList<Object>(rowCount);
                        ...if (originalModel.isRowAvailable()) {
                         rowKeys.add(rowKey);
                        ...

                        Here rowCount contains the total number of records in the database. (The number that I need). But rowKeys contains only 10 records returned from method walk(...) so rowKeys.size() is 10.
                        On the other hand getRowCount() must return 500. So don't you think that the correct implementation of getRowCount() is:
                        public int getRowCount() {
                         return originalModel.getRowCount();
                         }


                        In my project I use the following jars:
                        richfaces-api-3.2.2.BETA5.jar
                        richfaces-impl-3.2.2.BETA5.jar
                        richfaces-ui-3.2.2.BETA5.jar
                        which I've downloaded from this location:
                        http://repository.jboss.org/maven2/org/richfaces/ui/richfaces-ui/3.2.2.BETA5/

                        • 9. Re: Problem with ExtendedDataModel and rich:datascroller
                          konstantin.mishin

                          If you don't use attributes sortBy, filterBy and alike on any column inside dataTable org.richfaces.model.ModifiableModel mustn't be created.
                          See: UIDataTable.createDataModel() line 129

                          • 10. Re: Problem with ExtendedDataModel and rich:datascroller
                            hristo

                            Konstantin, thank you for this information.
                            Indeed when I removed all sortBy and filterBy attributes from my columns everything was ok.
                            But what if I want to have sortBy and filterBy attributes? In this case ModifiableModel is created and the issue exists.
                            Is it possible for me to inherit somehow from ModifiableModel and overwrite getRowCount()?

                            • 11. Re: Problem with ExtendedDataModel and rich:datascroller
                              konstantin.mishin

                              If you want to have sortBy and filterBy attributes you must implement org.richfaces.model.Modifiable
                              in your model.

                              • 12. Re: Problem with ExtendedDataModel and rich:datascroller
                                jalal.din

                                Hi,
                                I am also struggling with exactly same problem as mentioned by Hristo. I am also using the sortBy and filterBy as well. Main issues is that in following method

                                walk(FacesContext context, DataVisitor visitor, Range range, Object argument) throws IOException

                                int firstRow = ((SequenceRange)range).getFirstRow();
                                int numberOfRows = ((SequenceRange)range).getRows();

                                above variables are populated with 0 and -1 respectively. This leaves me to no option except populate all the data which results in fetching thousands of records. If I fetch only 8 or 10 records then it only shows one page. getRowCount always returns correct number of records as I have overriden it and it queries the database for count.

                                Pelase help.

                                Kind regards,
                                Jalal