Skip Headers
Oracle® Application Development Framework Developer's Guide For Forms/4GL Developers
10g (10.1.3.1.0)

Part Number B25947-01
Go to Documentation Home
Home
Go to Book List
Book List
Go to Table of Contents
Contents
Go to Index
Index
Go to Master Index
Master Index
Go to Feedback page
Contact Us

Go to previous page
Previous
Go to next page
Next
View PDF

27.1 Advanced View Object Concepts and Features

This section describes a number of interesting view object concepts and features that have not been discussed in previous chapters.

27.1.1 Using a Max Fetch Size to Only Fetch the First N Rows

The default maximum fetch size of a view object is minus one (-1), which indicates that there is no artificial limit to the number of rows that can be fetched. Keep in mind that by default, rows are fetched as needed, so this default does not imply a view object will necessary fetch all the rows. It simply means that if you attempt to iterate through all the rows in the query result, you will get them all.

However, you might want to put an upper bound on the maximum number of rows that a view object will retrieve. If you write a query containing an ORDER BY clause and only want to return the first N rows to display the "Top-N" entries in a page, you can call the setMaxFetchSize() method on your view object to set the maximum fetch size to N. The view object will stop fetching rows when it hits the maximum fetch size. Often you will combine this technique with specifying a Query Optimizer Hint of FIRST_ROWS on the Tuning panel of the View Object Editor. This gives a hint to the database that you want to retrieve the first rows as quickly as possible, rather than trying to optimize the retrieval of all rows.

27.1.2 Consistently Displaying New Rows in View Objects Based on the Same Entity

When multiple instances of entity-based view objects in an application module are based on the same underlying entity object, a new row created in one of them can be automatically added (without having to re-query) to the row sets of the others to keep your user interface consistent or simply to consistently reflect new rows in different application pages for a pending transaction. Consider the SRDemo application's SRList page that displays an end-user's list of service requests. If the end-user goes to create a new service request, this task is performed through a different view object and handled by a custom application module method. Using this view object new row consistency feature, the newly created service request automatically appears in the end-user's list of open service requests on the SRList page without having to re-query the database.

For historical reasons, this capability is known as the view link consistency feature because in prior releases of Oracle ADF the addition of new rows to other relevant row sets only was supported for detail view object instances in a view link based on an association. Now this view link consistency feature works for any view objects for which it is enabled, regardless of whether they are involved in a view link or not.

27.1.2.1 How View Link Consistency Mode Works

Consider two entity-based view objects ServiceRequestSummary and ServiceRequests both based on the same underlying ServiceRequest entity object. When a new row is created in a row set for one of these view objects (like ServiceRequests) and the row's primary key is set, any of the other row sets for view objects based on the same ServiceRequest entity object (like ServiceRequestSummary) receive an event indicating a new row has been created. If their view link consistency flag is enabled, then a copy of the new row is inserted into their row set as well.

27.1.2.2 Understanding the Default View Link Consistency Setting and How to Change It

You can control the default setting for the view link consistency feature using the jbo.viewlink.consistent configuration parameter. The default setting for this parameter is the word "DEFAULT" which has the following meaning. If your view object has:

  • A single entity usage, view link consistency is enabled

  • Multiple entity usages, and:

    • If all secondary entity usages are marked as contributing reference information, then view link consistency is enabled

    • If any secondary entity usage marked as not being a reference view link consistency is disabled.

You can globally disable this feature by setting the jbo.viewlink.consistent to the value false in your configuration. Conversely, you could globally enable this feature by setting jbo.viewlink.consistent to the value true, but Oracle does not recommend doing this. Doing so would force view link consistency to be set on for view objects with secondary entity usages that are not marked as a reference which presently do not support the view link consistency feature well.

To set the feature programmatically, use the setAssociationConsistent() API on any RowSet. When you call this method on a view object, it affects its default row set.

27.1.2.3 Using a RowMatch to Qualify Which New, Unposted Rows Get Added to a Row Set

If a view object has view link consistency enabled, any new row created by another view object based on the same entity object is added to its row set. By default the mechanism adds new rows in an unqualified way. If your view object has a design-time WHERE clause that queries only a certain subset of rows, you can apply a RowMatch object to your view object to perform the same filtering in-memory. The filtering expression of the RowMatch object you specify prevents new rows from being added that wouldn't make sense to appear in that view object.

For example, the ServiceRequestsByStatus view object in the SRDemo application includes a design time WHERE clause like this:

WHERE /* ... */ AND STATUS LIKE NVL(:StatusCode,'%') 

Its custom Java class overrides the create() method as shown in Example 27-1 to force view link consistency to be enabled. It also applies a RowMatch object whose filtering expression matches rows whose Status attribute matches the value of the :StatusCode named bind variable (or matches any row if :StatusCode = '%'). This RowMatch filter is used by the view link consistency mechanism to qualify the row that is a candidate to add to the row set. If the row qualifies by the RowMatch, it is added. Otherwise, it is not.

Example 27-1 Providing a Custom RowMatch to Control Which New Rows are Added

// In ServiceRequestsByStatusImpl.java
protected void create() {
  super.create();
  setAssociationConsistent(true);
  setRowMatch(new RowMatch("Status = :StatusCode or :StatusCode = '%'"));  
} 

See Section 27.5.4, "Performing In-Memory Filtering with RowMatch" for more information on creating and using a RowMatch object.


Note:

If the RowMatch facility does not provide enough control, you can override the view object's rowQualifies() method to implement a custom filtering solution. Your code can determine whether a new row qualifies to be added by the view link consistency mechanism or not.

27.1.2.4 Setting a Dynamic Where Clause Disables View Link Consistency

If you call setWhereClause() on a view object to set a dynamic where clause, the view link consistency feature is disabled on that view object. If you have provided an appropriate custom RowMatch object to qualify new rows for adding to the row set, you can call setAssociationConsistent(true) after setWhereClause() to re-enable view link consistency.

27.1.2.5 New Row from Other View Objects Added at the Bottom

If a row set has view link consistency enabled, then new rows added due to creation by other row sets are added to the bottom of the row set.

27.1.2.6 New, Unposted Rows Added to Top of RowSet when Re-Executed

If a row set has view link consistency enabled, then when you call the executeQuery() method, any qualifying new, unposted rows are added to the top of the row set before the queried rows from the database are added.

27.1.3 Understanding View Link Accessors Versus Data Model View Link Instances

View objects support two different styles of master-detail coordination:

  • View link instances for active data model master/detail coordination

  • View link accessor attributes for programmatically accessing detail row sets on demand

27.1.3.1 Enabling a Dynamic Detail Row Set with Active Master/Detail Coordination

When you add a view link instance to your application module's data model, you connect two specific view object instances and indicate that you want active master/detail coordination between the two. At runtime the view link instance in the data model facilitates the eventing that enables this coordination. Whenever the current row is changed on the master view object instance, an event causes the detail view object to be refreshed by automatically invoking executeQuery() with a new set of bind parameters for the new current row in the master view object.

A key feature of this active data model master/detail is that the master and detail view object instances are stable objects to which client user interfaces can establish bindings. When the current row changes in the master — instead of producing a new detail view object instance — the existing detail view object instance updates its default row set to contain a the set of rows related to the new current master row. In addition, the user interface binding objects receive events that allow the display to update to show the detail view object's refreshed row set.

Another key feature that is exclusive to active data model master/detail is that a detail view object instance can have multiple master view object instances. For example, an ExpertiseAreas view object instance may be a detail of both a Products and a Technicians view object instances. Whenever the current row in either the Products or Technicians view object instance changes, the default row set of the detail ExpertiseAreas view object instance is refreshed to include the row of expertise area information for the current technician and the current product. See Section 27.1.6, "Setting Up a Data Model with Multiple Masters" for details on setting up a detail view object instance with multiple-masters.

27.1.3.2 Accessing a Stable Detail Row Set Using View Link Accessor Attributes

When you need to programmatically access the detail row set related to a view object row by virtue of a view link, you can use the view link accessor attribute. You control the name of the view link accessor attribute on the View Link Properties panel of the View Link Editor. Assuming you've named your accessor attribute AccessorAttrName, you can access the detail row set using the generic getAttribute() API like:

RowSet detail = (RowSet)currentRow.getAttribute("AccessorAttrName");

If you've generated a custom view row class for the master view object and exposed the getter method for the view link accessor attribute on the client view row interface, you can write strongly-typed code to access the detail row set like this:

RowSet detail = (RowSet)currentRow.getAccessorAttrName();

Unlike the active data model master/detail, programmatic access of view link accessor attributes does not require a detail view object instance in the application module's data model. Each time you invoke the view link accessor attribute, it returns a RowSet containing the set of detail rows related to the master row on which you invoke it.

Using the view link accessor attribute, the detail data rows are stable. As long as the attribute value(s) involved in the view link definition in the master row remain unchanged, the detail data rows will not change. Changing of the current row in the master does not affect the detail row set which is "attached" to a given master row. For this reason, in addition to being useful for general programmatic access of detail rows, view link accessor attributes are appropriate for UI object like the tree control, where data for each master node in a tree needs to retain its distinct set of detail rows.

27.1.3.3 Accessor Attributes Create Distinct Row Sets Based on an Internal View Object

When you combine the use of active data model master/detail with programmatic access of detail row sets using view link accessor, it is even more important to understand that they are distinct mechanisms. For example, imagine that you have:

  • Defined ServiceRequests and ServiceHistories view objects

  • Defined a view link between them, naming the view link accessor HistoriesForRequest

  • Added instances of them to an application module's data model named master (of type ServiceRequests) and detail (of type ServiceHistories) coordinated actively by a view link instance.

If you find a service request in the master view object instance, the detail view object instance updates as expected to show the corresponding service request histories. At this point, if you invoke a custom method that programmatically accesses the HistoriesForRequest view link accessor attribute of the current ServiceRequests row, you get a RowSet containing the set of ServiceHistory rows. You might reasonably expect this programmatically access RowSet to have come from the detail view object instance in the data model, but this is not the case.

The RowSet returned by a view link accessor always originates from an internally created view object instance, not one you that added to the data model. This internal view object instance is created as needed and added with a system-defined name to the root application module.

The principal reason a distinct, internally-created view object instance is used is to guarantee that it remains unaffected by developer-related changes to their own view objects instances in the data model. For example, if the view row were to use the detail view object in the data model for view link accessor RowSet, the resulting row set could be inadvertently affected when the developer dynamically:

  1. Adds a WHERE clause with new named bind parameters

    If such a view object instance were used for the view link accessor result, unexpected results or an error could ensue because the dynamically-added WHERE clause bind parameter values have not been supplied for the view link accessor's RowSet: they were only supplied for the default row set of the detail view object instance in the data model.

  2. Adds an additional master view object instance for the detail view object instance in the data model.

    In this scenario, the semantics of the accessor would be changed. Instead of the accessor returning ServiceHistory rows for the current ServiceRequest row, it could all of a sudden start returning only the ServiceHistory rows for the current ServiceRequest that were created by a current technician, for example.

  3. Removes the detail view object instance or its containing application module instance.

    In this scenario, all rows in the programmatically-accessed detail RowSet would become invalid.

Furthermore, Oracle ADF needs to distinguish between the active data model master/detail and view link accessor row sets for certain operations. For example, when you create a new row in a detail view object, the framework automatically populates the attributes involved in the view link with corresponding values of the master. In the active data model master/detail case, it gets these values from the current row(s) of the possibly multiple master view object instances in the data model. In the case of creating a new row in a RowSet returned by a view link accessor, it populates these values from the master row on which the accessor was called.

27.1.4 Presenting and Scrolling Data a Page at a Time Using the Range

To present and scroll through data a page at a time, you can configure a view object to manage for you an appropriately-sized range of rows. The range facility allows a client to easily display and update a subset of the rows in a row set, as well as easily scroll to subsequent pages N rows as a time. You call setRangeSize() to define how many rows of data should appear on each page. The default range size is one (1) row. A range size of minus one (-1) indicates the range should include all rows in the row set.


Note:

When using the ADF Model layer's declarative data binding, the iterator binding in the page definition has a RangeSize property. At runtime, the iterator binding invokes the setRangeSize() method on its corresponding row set iterator, passing the value of this RangeSize property. The ADF design time by default sets this RangeSize property to 10 rows for most iterator bindings. An exception is the range size specified for a List binding to supply the set of valid values for a UI component like a dropdown list. In this case, the default range size is minus one (-1) to allow the range to include all rows in the row set.

When you set a range size greater than one, you control the row set paging behavior using the iterator mode. The two iterator mode flags you can pass to the setIterMode() method are:

  • RowIterator.ITER_MODE_LAST_PAGE_PARTIAL

    In this mode, the last page of rows may contain fewer rows than the range size. For example, if you set the range size to 10 and your row set contains 23 rows, the third page of rows will contain only three rows. This is the style that works best for web applications.

  • RowIterator.ITER_MODE_LAST_PAGE_FULL

    In this mode, the last page of rows is kept full, possibly including rows at the top of the page that had appeared at the bottom of the previous page. For example, if you set the range size to 10 and your row set contains 23 rows, the third page of rows will contain 10 rows, the first seven of which appeared as the last seven rows of page two. This is the style that works best for desktop-fidelity applications using Swing.

27.1.5 Efficiently Scrolling Through Large Result Sets Using Range Paging

As a general rule, for highest performance, Oracle recommends building your application in a way that avoids giving the end-user the opportunity to scroll through very large query results. To enforce this recommendation, call the getEstimatedRowCount() method on a view object to determine how many rows would be returned the user's query before actually executing the query and allowing the user to proceed. If the estimated row count is unreasonably large, your application can demand that the end-user provide additional search criteria.

However, when you must work with very large result sets, you can use the view object's access mode called "range paging" to improve performance. The feature allows your applications to page back and forth through data, a range of rows at a time, in a way that is more efficient for large data sets than the default "scrollable" access mode.

27.1.5.1 Understanding How to Oracle Supports "TOP-N" Queries

The Oracle database supports a feature called a "Top-N" query to efficiently return the first N ordered rows in a query. For example, if you have a query like:

SELECT EMPNO, ENAME,SAL FROM EMP ORDER BY SAL DESC

If you want to retrieve the top 5 employees by salary, you can write a query like:

SELECT * FROM (
   SELECT X.*,ROWNUM AS RN FROM (
      SELECT EMPNO,ENAME,SAL FROM EMP ORDER BY SAL DESC 
   ) X
) WHERE RN <= 5

which gives you results like:

EMPNO ENAME       SAL   RN
---------- -------- ------ ----
      7839 KING       5000    1
      7788 SCOTT      3000    2
      7902 FORD       3000    3
      7566 JONES      2975    4
      7698 BLAKE      2850    5

The feature is not only limited to retrieving the first N rows in order. By adjusting the criteria in the outmost WHERE clause you can efficiently retrieve any range of rows in the query's sorted order. For example, to retrieve rows 6 through 10 you could alter the query this way:

SELECT * FROM (
  SELECT X.*,ROWNUM AS RN FROM  (
     SELECT EMPNO,ENAME,SAL FROM EMP ORDER BY SAL DESC
  ) X
) WHERE RN BETWEEN 6 AND 10

Generalizing this idea, if you want to see page number P of the query results, where each page contains R rows, then you would write a query like:

SELECT * FROM (
  SELECT X.*,ROWNUM AS RN FROM (
    SELECT EMPNO,ENAME,SAL FROM EMP ORDER BY SAL DESC
  ) X
) WHERE RN BETWEEN ((:P - 1) * :R) + 1 AND (:P) * :R

As the result set you consider grows larger and larger, it becomes more and more efficient to use this technique to page through the rows. Rather than retrieving hundreds or thousands of rows over the network from the database, only to display ten of them on the page, instead you can produce a clever query to retrieve only the R rows on page number P from the database. No more than a handful of rows at a time needs to be returned over the network when you adopt this strategy.

To implement this database-centric paging strategy in your application, you could handcraft the clever query yourself and write code to manage the appropriate values of the :R and :P bind variables. Alternatively, you can use the view object's range paging access mode, which implements it automatically for you.

27.1.5.2 How to Enable Range Paging for a View Object

To enable range paging for your view object, first call setRangeSize() to define the number of rows per page, then call the following method:

yourViewObject.setAccessMode(RowSet.RANGE_PAGING);

27.1.5.3 What Happens When You Enable Range Paging

When a view object's access mode is set to RANGE_PAGING, the view object takes its default query like:

SELECT EMPNO, ENAME, SAL FROM EMP ORDER BY SAL DESC

and automatically "wraps" it to produce a Top-N query.

For best performance, the statement uses a combination of greater than and less than conditions instead of the BETWEEN operator, but the logical outcome is the same as the Top-N wrapping query you saw above. The actual query produced to wrap a base query of:

SELECT EMPNO, ENAME, SAL FROM EMP ORDER BY SAL DESC

looks like this:

SELECT * FROM (
  SELECT /*+ FIRST_ROWS */ IQ.*, ROWNUM AS Z_R_N FROM (
    SELECT EMPNO, ENAME, SAL FROM EMP ORDER BY SAL DESC
  ) IQ  WHERE ROWNUM < :0)
WHERE Z_R_N > :1

The two bind variables are bound as follows:

  • :1 index of the first row in the current page

  • :0 is bound to the last row in the current page

27.1.5.4 How are View Rows Cached When Using Range Paging?

When a view object operates in RANGE_PAGING access mode, it only keeps the current range (or "page") of rows in memory in the view row cache at a time. That is, if you are paging through results ten at a time, then on the first page, you'll have rows 1 through 10 in the view row cache. When you navigate to page two, you'll have rows 11 through 20 in the cache. This also can help make sure for large row sets that you don't end up with tons of rows cached just because you want to preserve the ability to scroll backwards and forwards.

27.1.5.5 How to Scroll to a Given Page Number Using Range Paging

When a view object operates in RANGE_PAGING access mode, to scroll to page number N call its scrollToRangePage() method, passing N as the parameter value.

27.1.5.6 Estimating the Number of Pages in the Row Set Using Range Paging

When a view object operates in RANGE_PAGING access mode, you can access an estimate of the total number of pages the entire query result would produce using the getEstimatedRangePageCount() method.

27.1.5.7 Accommodating Inserts and Deletes Using Auto Posting

The range paging access mode is typically used for paging through read-only row sets, and often is used with read-only view objects. You allow the user to find the row they are looking for by paging through a large row set with range paging access mode, then you use the Key of that row to find the selected row in a different view object for editing.

Additionally, the view object supports a RANGE_PAGING_AUTO_POST access mode to accommodate the inserting and deleting of rows from the row set. This mode behaves like the RANGE_PAGING mode, except that it eagerly calls postChanges() on the database transaction whenever any changes are made to the row set. This communicates the pending changes to the database via appropriate INSERT, UPDATE, or DELETE statements so that the changes are preserved when scrolling backward or forward.

27.1.5.8 Understanding the Tradeoffs of Using Range Paging Mode

You might ask yourself, "Why wouldn't I always want to use RANGE_PAGING mode?" The answer is that using range paging potentially causes more overall queries to be executed as you are navigating forward and backward through your view object rows. You would want to avoid using RANGE_PAGING mode in these situations:

  • You plan to read all the rows in the row set immediately (for example, to populate a dropdown list).

    In this case your range size would be set to -1 and there really is only a single "page" of all rows, so range paging does not add value.

  • You need to page back and forth through a small-sized row set.

    If you have 100 rows or fewer, and are paging through them 10 at a time, with RANGE_PAGING mode you will execute a query each time you go forward and backward to a new page. In normal mode, you will cache the view object rows as you read them in, and paging backwards through the previous pages will not re-execute queries to show those already-seen rows.

In the case of a very large (or unpredictably large) row set, the trade off of potentially doing a few more queries — each of which only returns up to the RangeSize number of rows from the database — is more efficient then trying to cache all of the previously-viewed rows. This is especially true if you allow the user to jump to an arbitrary page in the list of results. Doing so in normal, scrollable mode requires fetching and caching all of the rows between the current page and the page the users jumps to. In RANGE_PAGING mode, it will ask the database just for the rows on that page. Then, if the user jumps back to a page of rows that they have already visited, in RANGE_PAGING mode, those rows get re-queried again since only the current page of rows is held in memory in this mode.

27.1.6 Setting Up a Data Model with Multiple Masters

When useful, you can set up your data model to have multiple master view object instances for the same detail view object instance. Consider view objects named Technicians, Products, and ExpertiseAreas with view links defined between:

  • Products and ExpertiseAreas

  • Technicians and ExpertiseAreas


Note:

The example in this section refer to the MultipleMasters project in the AdvancedViewObjectExamples workspace. See the note at the beginning of this chapter for download instructions.

Figure 27-1 shows what the data model panel looks like when you've configured both Technicians and Products view object instances to be masters of the same ExpertiseAreas view object instance.

Figure 27-1 Multiple Master View Object Instances for the Same Detail

Image of Data Model panel

To set up the data model as shown in Figure 27-1 open the Application Module Editor and follow these steps on the Data Model panel:

  1. Add an instance of the Technicians view object to the data model.

    Assume you name it Technicians.

  2. Add an instance of the Products view object to the data model

    Assume you name it Products.

  3. Select the Technicians view object instance in the Data Model list

  4. In the Available View Objects list, select the ExpertiseAreas view object indented beneath the Technicians view object, enter the view object instance name of ExpertiseAreas in the Name field, and click > to shuttle it into data model as a detail of the existing Technicians view object instance.

  5. Select the Products view object instance in the Data Model list

  6. In the Available View Objects list, select the ExpertiseAreas view object indented beneath the Products view object, enter the same view object instance name of ExpertiseAreas in the Name field, and click > to shuttle it into data model as a detail of the existing Products view object instance.

    An alert will appear: An instance of a View Object with the name ExpertiseAreas has already been used in the data model. Would you like to use the same instance?

  7. Click Yes to confirm you want the ExpertiseAreas view object instance to also be the detail of the Products view object instance.

27.1.7 Understanding When You Can Use Partial Keys with findByKey()

View objects based on multiple entity usages support the ability to find view rows by specifying a partially populated key. A partial key is a multi-attribute Key object with some of its attributes set to null. However, there are strict rules about what kinds of partial keys can be used to perform the findByKey().

If a view object is based on N entity usages, where N > 1, then the view row key is by default comprised of all of the primary key attributes from all of the participating entity usages. Only the ones from the first entity object are required to participate in the view row key, but by default all of them do.

If you allow the key attributes from some secondary entity usages to remain as key attributes at the view row level, then you should leave all of the attributes that form the primary key for that entity object as part of the view row key. Assuming you have left the one or more key attributes in the view row for M of the N entity usages, where (M <= N), then you can use findByKey() to find rows based on any subset of these M entity usages. Each entity usage for which you provide values in the Key object, requires that you must provide non-null values for all of the attributes in that entity's primary key.

You have to follow this rule because when a view object is based on at least one or more entity usages, its findByKey() method finds rows by delegating to the findByPrimaryKey() method on the entity definition corresponding to the first entity usage whose attributes in the view row key are non-null. The entity definition's findByPrimaryKey() method requires all key attributes for any given entity object to be non-null in order to find the entity row in the cache.

As a concrete example, imagine that you have a ServiceRequests view object with an ServiceRequest entity object as its primary entity usage, and a Product entity as secondary reference entity usage. Furthermore, assume that you leave the Key Attribute property of both of the following view row attributes set to true:

  • SvrId — primary key for the ServiceRequest entity

  • ProdId1 — primary key for the Product entity

The view row key will therefore be the (SvrId, ProdId1) combination. When you do a findByKey(), you can provide a Key object that provides:

  • A completely specified key for the underlying ServiceRequest entity

    Key k = new Key(new Object[]{new Number(200), null});
    
    
  • A completely specified key for the underlying Product entity

    Key k = new Key(new Object[]{null, new Number(118)}); 
    
    
  • A completely specified key for both entities

    Key k = new Key(new Object[]{new Number(200), new Number(118)});
    
    

When a valid partial key is specified, the findByKey() method can return multiple rows as a result, treating the missing entity usage attributes in the Key object as a wildcard.

27.1.8 Creating Dynamic Attributes to Store UI State

You can add one or more dynamic attributes to a view object at runtime using the addDynamicAttribute() method. Dynamic attributes can hold any object as their value. Typically, you will consider using dynamic attributes when writing generic framework extension code that requires storing some additional per-row transient state to implement a feature you want to add to the framework in a global, generic way.

27.1.9 Working with Multiple Row Sets and Row Set Iterators

While you typically work with a view object's default row set, you can call the createRowSet() method on the ViewObject interface to create secondary, named row sets based on the same view object's query. One situation where this could make sense is when your view object's SQL query contains named bind variables. Since each RowSet object stores its own copy of bind variable values, you could use a single view object to produce and process multiple row sets based on different combinations of bind variables values. You can find a named row set you've created using the findRowSet() method. When you're done using a secondary row set, call its closeRowSet() method.

For any RowSet, while you typically work with its default row set iterator, you can call the createRowSetIterator() method of the RowSet interface to create secondary, named row set iterators. You can use find a named row set iterator you've created using the findRowSetIterator() method. When you're done using a secondary row set iterator, call its closeRowSetIterator() method.


Note:

Through the ADF Model declarative data binding layer, user interface pages or panels in your application work with the default row set iterator of the default row set of view objects in the application module's data model. Due to this fact, the most typical scenario for creating secondary row set iterators is to write business logic that iterates over a view object's default row set without disturbing the current row of the default row set iterator used by the user interface layer.

27.1.10 Optimizing View Link Accessor Access By Retaining the Row Set

Each time you retrieve a view link accessor row set, by default the view object creates a new RowSet object to allow you to work with the rows. This does not imply re-executing the query to produce the results each time, only creating a new instance of a RowSet object with its default iterator reset to the "slot" before the first row. To force the row set to refresh its rows from the database, you can call its executeQuery() method.

Since there is a small amount of overhead associated with creating the row set, if your code makes numerous calls to the same view link accessor attributes you can consider enabling view link accessor row set retention for the source view object in the view link. To use the view link accessor retention feature, enable a custom Java class for your view object, override the create() method, and add a line after super.create() that calls the setViewLinkAccessorRetained() method passing true as the parameter. It affects all view link accessor attributes for that view object.

When this feature is enabled for a view object, since the view link accessor row set it not recreated each time, the current row of its default row set iterator is also retained as a side-effect. This means that your code will need to explicitly call the reset() method on the row set you retrieve from the view link accessor to reset the current row in its default row set iterator back to the "slot" before the first row.

Note, however, that with accessor retention enabled, your failure to call reset() each time before you iterate through the rows in the accessor row set can result in a subtle, hard-to-detect error in your application. For example, if you iterate over the rows in a view link accessor row set like this, for example to calculate some aggregate total:

RowSet rs = (RowSet)row.getAttribute("ServiceRequestsForProduct");
while (rs.hasNext()) {
  Row r = rs.next();
  // Do something important with attributes in each row
}

The first time you work with the accessor row set the code will work. However, since the row set (and its default row set iterator) are retained, the second and subsequent times you access the row set the current row will already be at the end of the row set and the while loop will be skipped since rs.hasNext() will be false. Instead, with this feature enabled, write your accessor iteration code like this:

RowSet rs = (RowSet)row.getAttribute("ServiceRequestsForProduct");
rs.reset(); // Reset default row set iterator to slot before first row!
while (rs.hasNext()) {
  Row r = rs.next();
  // Do something important with attributes in each row
}

Recall that if view link consistency is on, when the accessor is retained the new unposted rows will show up at the end of the row set. This is slightly different from when the accessor is not retained (the default), where new unposted rows will appear at the beginning of the accessor row set.