Iterating a view object using a secondary rowset iterator

There are times when you need to iterate through a view object rowset programmatically. In this recipe, we will see how to do this using a secondary rowset iterator. We will iterate over the Employees rowset and increase the employee's commission by a certain percentage for each employee that belongs to the Sales department.

Getting ready

This recipe was developed using the HRComponents workspace, which was created in the Overriding remove() to delete associated children entities recipe in Chapter 2, Dealing with Basics: Entity Objects. The HRComponents workspace requires a database connection to the HR schema.

How to do it...

  1. Open the Employees view object definition and go to the Java page.
  2. Click on the Edit java options button (the pen icon) to open the Select Java Options dialog.
  3. Click on the Generate View Object Class and Generate View Row Class checkboxes. Ensure that the Include accessors checkbox is also selected.
  4. Click OK to proceed with the creation of the custom implementation classes.
  5. Add the following helper method to EmployeesImpl.java. If the import dialog is shown for the Number class, make sure that you choose the oracle.jbo.domain.Number class.
    public void adjustCommission(Number commissionPctAdjustment) {
      // check for valid commission adjustment
      if (commissionPctAdjustment != null) {
        // create an employee secondary rowset iterator
        rowsetIterator employees = this.createrowsetIterator(null);
        // reset the iterator
        employees.reset();
        // iterate the employees
        while (employees.hasNext()) {
          // get the employee
          EmployeesRowImpl employee = (EmployeesRowImpl)employees.next();
          // check for employee belonging to the sales department
          if (employee.getDepartmentId() != null &&SALES_DEPARTMENT_ID ==employee.getDepartmentId().intValue()) {
            // calculate adjusted commission
            Number commissionPct = employee.getCommissionPct();
            Number adjustedCommissionPct = commissionPct != null) ? commissionPct.add(commissionPctAdjustment) : commissionPctAdjustment;
            // set the employee's new commission
            employee.setCommissionPct(adjustedCommissionPct);
          }
        }
        // done with the rowset iterator
        employees.closerowsetIterator();
      }
    }
  6. On the Employees Java page click on the Edit view object client interface button (the pen icon).
  7. On the Edit Client Interface dialog, shuttle the adjustCommission() method to the Selected list and click OK.
    How to do it...
  8. Open the HRComponentsAppModule application module definition and go to the Java page.
  9. Click on the Edit java options button.
  10. On the Select Java Options dialog, click on the Generate Application Module Class checkbox. Then click OK to close the dialog.
  11. Open the HrComponentsAppModuleImpl class and add the following method:
    public void adjustCommission(Number commissionPctAdjustment) {
      // execute the Employees view object query to create a rowset
      this.getEmployees().executeQuery();
      // adjust the employees commission
      this.getEmployees().adjustCommission(commissionPctAdjustment);
    }
  12. Return to the application module definition Java page, then use the Edit application module client interface button to add the adjustCommission() method to the application module's client interface.

How it works...

We created a view object custom Java implementation class for the Employees view object and add a method called adjustCommission() . The method is then exposed to the view object's client interface so that it can be accessible and called using the Employees interface.

The adjustCommission() method adjusts the commission for all employees belonging to the Sales department. The method accepts the commission adjustment percentage as an argument. We call the createrowsetIterator() method to create a secondary iterator, which we then use to iterate over the Employees rowset. This is the recommended practice to perform programmatic iteration over a rowset. The reason is that the view object instance that is being iterated may be bound to UI components and that iterating it directly will interfere with the UI. In this case, you will see the current row changing by itself.

We then call the reset() method to initialize the rowset iterator. This places the iterator in the slot before the first row in the rowset. We iterate the rowset by checking whether a next row exists. This is done by calling hasNext() on the iterator. If a next row exists, we retrieve it by calling next(), which returns an oracle.jbo.Row. We cast the default Row object that is returned to an EmployeesRowImpl , so we can use the custom setter and getter methods to manipulate the Employee row.

For testing purposes, we create a custom application module implementation class and add a method called adjustCommission() to it. We expose this method to the application module client interface so that we can call it from the ADF Model Tester . Note that methods can also be added to the view object client interface. Then these methods are shown under the view object collection in the Data Control panel and can be bound to the JSF page simply by dropping them on the page. Inside the adjustCommission(), we execute the Employees view object query by calling executeQuery() on it. We get the Employees view object instance via the getEmployees() getter method. Finally, we call the adjustCommission() method that we implemented in EmployeesImpl to adjust the employees' commission.

How it works...

There's more...

In order to be able to iterate a view object rowset using a secondary iterator, the view object access mode in the General | Tuning section must set to Scrollable . Any other access mode setting will result in a JBO-25083: Cannot create a secondary iterator on row set {0} because the access mode is forward-only or range-paging error when attempting to create a secondary iterator. To iterate view objects configured with range paging, use the range paging view object API methods. Specifically, call getEstimatedRangePageCount() to determine the number of pages and for each page call scrollToRangePage() . Then determine the range page size by calling getRangeSize() and iterate through the page calling getRowAtRangeIndex() .

Pitfalls when iterating over large rowsets

Before iterating a view object rowset, consider that iterating the rowset may result in fetching a large number of records from the database to the middle layer. In this case, other alternatives should be considered, such as running the iteration asynchronously on a separate Work Manager , for instance (see recipe Using a Work Manager for processing of long running tasks in Chapter 12, Optimizing, Fine-tuning and Monitoring). In certain cases, such as when iterating in order to compute a total amount, consider using any of the following techniques. These methods are far more optimized in determining the total amount for an attribute than iterating the view object using Java code.

  • Groovy expressions such as object.getRowSet().sum('SomeAttribute')
  • Analytic functions, such as COUNT(args) OVER ([PARTITION BY <…>] …), in the view object's SQL query

For instance, consider the following view object query that calculates the department's total salaries using an analytic function. This would have been much more costly if it had to be done programmatically by iterating the underlying view objects.

SELECT DISTINCT DEPARTMENTS.DEPARTMENT_NAME,
SUM (EMPLOYEES.SALARY) OVER (PARTITION BY EMPLOYEES.DEPARTMENT_ID)
AS DEPARTMT_SALARIES
FROM EMPLOYEES
INNER JOIN DEPARTMENTS
ON DEPARTMENTS.DEPARTMENT_ID = EMPLOYEES.DEPARTMENT_ID
ORDER BY DEPARTMENTS.DEPARTMENT_NAME

See also

  • Overriding remove() to delete associated children entities, Chapter 2, Dealing with Basics: Entity Objects