PeopleCode | Additional constructs for accessing a component interface
A. Introduction
Tip 018 got us started with using component interfaces, so what follows is some additional functionality for processing data through a CI.
B. Searching a Collection for a Specific Item
You may have defined a collection in your CI and now you want to search the collection to see if a particular key combination exists. You can do this by using the ‘ItembyKeys’ method:
&oStdntCarTerm = &oStdntCarTermCollection.ItembyKeys(&institution, &strm); If oStdntCarTerm <> Null then /* Match Found */ Else /* Match not found */ End-if;
If the search is successful, the item object (&oStdntCarTerm) will be set to the matching item in the collection. If no match is found, &oStdntCarTerm will be set to Null.
Sometimes you may not be certain what the keys are, or what order they should be entered in as part of the ‘ItembyKeys’ method. In this case, open up the component interface in App Designer and inspect the collection to see which fields have the ‘key’ symbol printed next to them. In the following example, the collection ‘ACAD_PROG_1’ has two keys – Effective Date (EFFDT) and Effective Sequence (EFFSEQ). Both these values would need to be specified in the ‘ItembyKeys’ method.
C. Inserting a New Item into a Collection
In this case, you have defined a collection on the CI and now you would like to insert a new row into the collection. This would be the equivalent of hitting the ‘+’ button on an online page. Because PeopleSoft collections are effectively rowsets in disguise, they will always have an initial blank row on creation. This means we need to check whether the rowset is blank before deciding whether to insert a new item. If we discover that item 1 of the rowset is currently blank, then we can go ahead and use item 1 for our new item. If however, data is present in item 1, we will need to insert a new item.
If &oStdntAdvrHistCollection.Item(1).ADVISOR_ID = "" Then &oStdntAdvrHist = &oStdntAdvrHistCollection.Item(1); Else &oStdntAdvrHist = &oStdntAdvrHistCollection.InsertItem(1); End-If;
D. Deleting an Item from a Collection
Deleting an item from a collection is a fairly straightforward task. After you’ve identified the item number that needs to be deleted, you can go ahead and perform a ‘DeleteItem’ on the collection.
If &oAcadProg1.PROG_ACTION = "DATA" And &oAcadProg1.PROG_REASON = "XXXX" Then &oAcadProg1 = &oAcadProg1Collection.DeleteItem(&i); End-If;
In this case, the code was looping through a collection searching for matches on two of the fields. As soon as a match is found, the item is deleted from the collection.
E. Coding for CI Errors
The final point concerning CIs is not a specific piece of code as such, but an approach to follow when implementing a CI for a large quantity of records. Normally you would not want your process to terminate on encountering a CI error. Instead, you would prefer the process to continue selecting all records, gracefully logging any errors that are encountered along the way. However, many developers discover that as soon as a CI error occurs, this terminates the process prematurely.
This happens due to the fact that CI errors have the side effect of terminating any currently open SQL cursors. If a ‘DoSelect’, or any other form of SQL ‘select’ is in process, no further records will be selected and the program will error when it tries to fetch from an SQL cursor that no longer exists. Therefore, as we’ll see below, if you want to properly catch all CI errors without terminating the process, perform any SQL processing in advance, and then use a non-SQL approach – such as a Rowset object – within the CI itself.
Furthermore, when you first create a CI, the CI objects and properties are initialised and held in the server’s memory. As you continue to create further CI objects inside the same program, additional memory space is reserved for each new object. Therefore, if you are working with 1000 records for instance, this can consume a significant amount of machine resources as you would be opening the same CI object 1000 times. A summary of such an approach would be:
- Loop through each record to be processed (perhaps in a ‘DoSelect’
- Open the CI for the record
- Process the CI, save and close.
A more efficient approach is to only open the CI once and then loop through the records within the CI code itself. You could, for instance, pre-populate a rowset with all the data required for the CI. This solves two problems in one: (1) it means the CI object only needs to be initialised once, and (2) it performs all SQL processing in advance of the CI, thus ensuring that no SQL cursors will be terminated by CI errors.
The CI approach should now appear as follows:
- Loop through each record to be processed (for instance, a ‘DoSelect’)
- Build a rowset of the data to be processed
- Open the CI once
- Loop through each record in the rowset one-at-a-time.
- Process the CI, save and close and resume to the next iteration of the loop
As this process continues, errors are noted and logged, without causing the entire program to terminate prematurely. It’s also more efficient due to only opening the CI object once.
See Also:
Tip 018: Basic Component Interface Code