Search This Blog

Tuesday, 30 April 2013

ViewObject. Working with multiple RowSets


ViewObject. Working with multiple RowSets.

Let's say we have a ViewObject with quite "heavy" SQL query from performance point of view. We need to show ViewObject's rows in two different tables on the same page and rows in the tables should be filtered in different ways. For example, we have a query from Employees table and we need to show separately clerks in one table and managers in another one. And let's suppose that the query is very heavy, so it's preferable to be executed once only. It would be nice to retrieve records from database once and after that filter them in memory and show in appropriate tables as many times as we need.
In most cases we work with ViewObjects containing one "Default" RowSet only. ViewObject creates it internally and implementing RowSet interface delegates it's methods to the "Default" RowSet. But ViewObject can support more than one RowSet. Except internally created "Default" RowSet we can create "secondary" RowSets. This feature can be very useful for our usecase. We're going to use "Default" RowSet to retrieve all rows from database and create two "secondary" RowSets (clerks and managers) with filtered in memory rows. These "secondary" RowSets we will show in our tables on the page.

In the model of our sample application we have very simple (just for example) entity based ViewObjectEmployeesView with two ViewCiterias - EmployeesViewCriteriaClerk andEmployeesViewCriteriaMAN:




In EmployeesViewImpl we have a method that creates new "secondary" RowSet as a result of filtering in memory rows from main "Default" rowset. It uses one of our ViewCriterias to filter the rows:

  1.     private RowSet getRowSet(String rowSetName, String criteriaName) {  
  2.         //Find created secondary rowset by name  
  3.         ViewRowSetImpl rs = (ViewRowSetImpl)findRowSet(rowSetName);  
  4.   
  5.         //if not found  
  6.         if (rs == null) {  
  7.             //Create new rowset as a result of filtering in memory rows  
  8.             //from DefaultRowSet using ViewCriteria criteriaName  
  9.             rs =  
  10.                (ViewRowSetImpl)findByViewCriteria(getViewCriteria(criteriaName), -1,  
  11.                                      ViewObject.QUERY_MODE_SCAN_VIEW_ROWS);  
  12.   
  13.             //RowSet is created with autogenerated name like "EmployeesView1_...  
  14.             //Let's remove the rowset from VO's rowsets table.             
  15.             removeRowSet(rs);  
  16.             //Change rowset's name.   
  17.             rs.setName(rowSetName);  
  18.             //And put it back. Next time we'll be able to find it by name.   
  19.             addRowSet(rs);  
  20.   
  21.         }  
  22.   
  23.         return rs;  
  24.   
  25.     }  


And two methods-clients of the getRowSet method:

  1.     private static String CLERK_RS = "ClerkRowSet";  
  2.     private static String MAN_RS = "ManRowSet";  
  3.     private static String CLERK_CRITERIA = "EmployeesViewCriteriaClerk";  
  4.     private static String MAN_CRITERIA = "EmployeesViewCriteriaMAN";  
  5.       
  6.     //Get RowSet for clerks  
  7.     public RowSet getClerkRowSet () {  
  8.       return getRowSet(CLERK_RS, CLERK_CRITERIA);  
  9.       
  10.     }  
  11.       
  12.     //Get RowSet for managers   
  13.     public RowSet getManRowSet () {  
  14.       return getRowSet(MAN_RS, MAN_CRITERIA);    
  15.     }   

These two methods should be exposed via client interface to be accessible from the binding layer.

In our View we have the following TaskFlow:


The first activity is a method call, executing query of EmployeesView instance. So, on this step we're going to retrieve rows from the database. In order to retrieve all rows, be sure, that Fetch Mode attribute of the ViewObject is set to FETCH_ALL.


View activity MainView contains two tables for clerks and managers. Let's have a look at its pageDef:
  1.   <executables>  
  2.     <variableIterator id="variables"/>  
  3.   
  4.     <methodIterator Binds="getClerkRowSet.result"  
  5.                     DataControl="AppModuleDataControl" RangeSize="25"  
  6.                     id="getClerkRowsIterator"/>  
  7.       
  8.     <methodIterator Binds="getManRowSet.result"  
  9.                     DataControl="AppModuleDataControl" RangeSize="25"  
  10.                     id="getManRowSetIterator"/>  
  11.   </executables>  
  12.   <bindings>  
  13.      
  14.     
  15.     <tree IterBinding="getClerkRowsIterator" id="EmployeesView11">  
  16.       <nodeDefinition DefName="com.cs.blog.testfilterVO.model.EmployeesView">  
  17.         <AttrNames>  
  18.           <Item Value="EmployeeId"/>  
  19.           <Item Value="FirstName"/>  
  20.           <Item Value="LastName"/>  
  21.           <Item Value="Email"/>  
  22.           <Item Value="PhoneNumber"/>  
  23.           <Item Value="HireDate"/>  
  24.           <Item Value="JobId"/>  
  25.           <Item Value="Salary"/>  
  26.           <Item Value="CommissionPct"/>  
  27.           <Item Value="ManagerId"/>  
  28.           <Item Value="DepartmentId"/>  
  29.           <Item Value="CreatedBy"/>  
  30.           <Item Value="CreatedDate"/>  
  31.           <Item Value="ModifiedBy"/>  
  32.           <Item Value="ModifiedDate"/>  
  33.           <Item Value="ActionComment"/>  
  34.         </AttrNames>  
  35.       </nodeDefinition>  
  36.     </tree>  
  37.     <tree IterBinding="getManRowSetIterator" id="EmployeesView12">  
  38.       <nodeDefinition DefName="com.cs.blog.testfilterVO.model.EmployeesView">  
  39.         <AttrNames>  
  40.           <Item Value="EmployeeId"/>  
  41.           <Item Value="FirstName"/>  
  42.           <Item Value="LastName"/>  
  43.           <Item Value="Email"/>  
  44.           <Item Value="PhoneNumber"/>  
  45.           <Item Value="HireDate"/>  
  46.           <Item Value="JobId"/>  
  47.           <Item Value="Salary"/>  
  48.           <Item Value="CommissionPct"/>  
  49.           <Item Value="ManagerId"/>  
  50.           <Item Value="DepartmentId"/>  
  51.           <Item Value="CreatedBy"/>  
  52.           <Item Value="CreatedDate"/>  
  53.           <Item Value="ModifiedBy"/>  
  54.           <Item Value="ModifiedDate"/>  
  55.           <Item Value="ActionComment"/>  
  56.         </AttrNames>  
  57.       </nodeDefinition>  
  58.     </tree>  
  59.     <methodAction id="getManRowSet" RequiresUpdateModel="true"  
  60.                   Action="invokeMethod" MethodName="getManRowSet"  
  61.                   IsViewObjectMethod="true" DataControl="AppModuleDataControl"  
  62.                   InstanceName="AppModuleDataControl.EmployeesView1"  
  63.                   ReturnName="AppModuleDataControl.methodResults.getManRowSet_AppModuleDataControl_EmployeesView1_getManRowSet_result"/>  
  64.     <methodAction id="getClerkRowSet" RequiresUpdateModel="true"  
  65.                   Action="invokeMethod" MethodName="getClerkRowSet"  
  66.                   IsViewObjectMethod="true" DataControl="AppModuleDataControl"  
  67.                   InstanceName="AppModuleDataControl.EmployeesView1"  
  68.                   ReturnName="AppModuleDataControl.methodResults.getClerkRowSet_AppModuleDataControl_EmployeesView1_getClerkRowSet_result"/>  
  69.   
  70.   </bindings>  
Note, that Instead of Iterators we use methodIterators representing results of methodActionsgetManRowSet and getClerkRowSet and these methodIterators are set in IterBinding attributes of tree bindings EmployeesView11 and EmployeesView12 that are  used by our tables on the page.

The result of our work looks like this:


No comments:

Post a Comment