Showing posts with label Row set. Show all posts
Showing posts with label Row set. Show all posts

17 Sept 2013

Populating tables with method iterator

Sometimes it can be useful to provide the data collection for a table component by some custom method in the service layer. An example of this technique can be found here. In this case we use methodAction to invoke the method and methodIterator to represent method's return value as a data collection for the table.
Let's say in our EmployeesView view object we've got a method returning some secondary custom ViewObject's row set:
   public RowSet getManagers(){   
    RowSet rs = (RowSet) findByViewCriteria(getViewCriteria("ManagersCriteria"), -1,  
                              ViewObject.QUERY_MODE_SCAN_DATABASE_TABLES);  
    return rs;       
  }


In the PageDef file we've got methodAction invoking this method:
<methodAction id="getManagers" RequiresUpdateModel="true"
    Action="invokeMethod" MethodName="getManagers"
    IsViewObjectMethod="true"
    DataControl="AppModuleDataControl"
    InstanceName="data.AppModuleDataControl.EmployeesView"
    ReturnName="data.AppModuleDataControl.methodResults.getManagers_AppModuleDataControl_EmployeesView_getManagers_result"
    />


The methodIterator:
    <methodIterator Binds="getManagers.result"
                    DataControl="AppModuleDataControl" RangeSize="25"
                    id="getManagersIterator"/>
 
And the tree definition:
    <tree IterBinding="getManagersIterator" id="VEmployees1">
      <nodeDefinition DefName="com.cs.blog.appmethoditerator.model.EmployeesView"
                      Name="VEmployees10">
        <AttrNames>
          <Item Value="EmployeeId"/>
          <Item Value="FirstName"/>
          <Item Value="LastName"/>
        </AttrNames>
      </nodeDefinition>
    </tree>


The table which is based on this structure looks like this:


Everything seems to be fine. But, actually, it's not. If we try to sort our data in the table, there will be no any effect. The getManagers method is going to return new row set without any bothering about applied sort criteria. Actually the framework applies the sort criteria to the EmployeesView view object, but not to the row set, returning by the getManagers method. On the other hand, this secondary row set is populated by some internal helper view object, which is called finder view object. And this finder view object has no any idea about changed OrderBy clause. We can fix that overriding ViewObject's method createFinderVO:

  protected ViewObjectImpl createFinderVO(String suffix) 
  {
    ViewObjectImpl vo = super.createFinderVO(suffix);
    //Get OrderBy clause from the parent VO and set it up for the finder VO 
    vo.setOrderByClause(getOrderByClause());
    return vo;                                                           
  }


And now everything works really fine.

That's it!

31 May 2012

Multiple iterator bindings for one View Object

The common practice (and default option for the declarative approach) is to create one iterator binding per View Object in the Page Def file.  But there's nothing to prevent us from defining several iterators in the PageDef's executable section for the same View Object. By default iterator binding binds to default row set iterator of the View Object. Iterator binding has RSIName attribute which allows us to bind to the named row set iterator of the View Object. When it could be an option? Let's assume we have a View Object with a bind variable in its query and  we need to show on the same page two separate results of the query with different values of the bind variable:

select * from Employees
where job_id = :job_id 

As we know View Object can have many secondary row sets besides its main default row set which is used by default. Every row set can store its own set of bind variable values. The view links functionality is based on this feature. We are going to use it as well. So, we have our ViewObjectImpl class with two overridden methods:

  protected void create() { 
    super.create(); 
    
    //Create Row Set for clerks and define value for the job_id bind variable
    ViewRowSetImpl rsClerk = (ViewRowSetImpl) createRowSet("ClerkRSI");
    rsClerk.setExecuteParameters(null, 
                    new Object[] { new Object[] {"job_id", "ST_CLERK"}}, false);       

    //Create Row Set for managers and define value for the job_id bind variable
    ViewRowSetImpl rsMan = (ViewRowSetImpl) createRowSet("ManRSI");
    rsMan.setExecuteParameters(null,
                    new Object[] { new Object[] {"job_id", "ST_MAN"}}, false);       

    }
  
   public oracle.jbo.RowSetIterator findRowSetIterator(java.lang.String p1) {
       RowSetIterator rsi = super.findRowSetIterator(p1);        
       if (rsi == null) 
          //Probably we are looking for  ClerkRSI or ManRSI
           return findRowSet(p1);
        return rsi; 
      }


And in our Page Def file we have two iterator bindings:

    <iterator Binds="VEmp" RangeSize="25" DataControl="AppModuleDataControl"
              id="VEmpClerkIterator" RSIName="ClerkRSI"/>
    <iterator Binds="VEmp" RangeSize="25" DataControl="AppModuleDataControl"
              id="VEmpManagerIterator" RSIName="ManRSI"/>


 
These bindings can be used to put two separate tables on our page with clerks and managers.

That's it!