An Example of using the CI Find Method
By Chris Malek | Tue, Jun 16, 2015
Find method on the component Interface API is poorly documented in
the Component Interface Section of
I thought it would be useful to provide a real world example of its
usage that I have found at a couple of clients.
Setting Up the Situation
In the Campus Solutions product, there is the Course Catalog component that allows you to maintain the catalog. The search record on the component can return strange results that I find often confuses users. Let’s look at an example search from a Demo instance in the screen-shot below. Let’s say that a user was searching for the Subject/Catalog of ‘ENGLLIT/231A’ using the search record.
If you look closely at this search, it returned two rows. Those two search result rows actually point to the exact same unique value CRSE_ID of “002082” in the component. You can click on either one and the exact same data will load. You could have also search for the “Course ID” of “002082” and you would have gotten back these same search result pictured above with two rows.
Again you can click on any of the search results and it takes you to the same place.
This is strange behavior, why is it doing this? From a functional perspective this makes sense as the course name can change over time. However, those name changes are just an insertion of an effective date on the same course. If someone always knew the class as the old “Poetry I” description they should be able to search for that and find the result. Once they get to the result and open the component, they would see that the course name had changed to “Poetry” on some effective date. If the search record had only returned the most effective row, the user would not be able to find a result under “Poetry I” which could be problematic especially if the course had undergone a more drastic name change like “Accounting Fundamentals” to “Business Accounting”.
I have discussed this “feature” with countless users over the years. They will search for a course and when they see two or three results for the same CRSE_ID, they think there was some data corruption or duplicate value. Additionally, they don’t know which one to click on when in reality they all go to the same place.
If we take a quick look at the record definition of the CRSE_CATALOG record. We see that there are just two keys on the record: CRSE_ID & EFFDT. There would be no way to introduce a duplicate CRSE_ID to the record.
So we see that a search record can return “duplicate” values but when the component actually loads the data from the database, it pulls the same key values from the database. When a user selects a search result row, they are really telling the component processor to load into the component whatever matching keys exists between the underlying component and the search record. In the case of the CS course catalog this is the CRSE_ID key.
This is a very subtle point to understand which leads into what I really want to show in this article.
Special Handling for Component Interface
When this behavior manifests itself on a search record and the component
is being called through a Component Interface, special handling and code
has to be in place to have the Component Interface code work. You have
to make use of the
find method on the component interface which is
poorly documented in PeopleBooks and it does not contain a real world
In the code examples below, we will mimic the same process above that we performed in the web browser using PeopleCode and Component Interface to show the special handling required in this situation.
First we will setup the standard CI variables.
Local ApiObject &oSession, &oCrseCatalog; &oSession = %Session; &oSession.PSMessagesMode = 1; /* MESSAGE COLLECTION */ &oCrseCatalog = &oSession.GetCompIntfc(CompIntfc.X_CRSE_CATALOG); &oCrseCatalog.InteractiveMode = True; &oCrseCatalog.GetHistoryItems = True; &oCrseCatalog.EditHistoryItems = True;
In the next section is where we need some special handling.
- First we set our unique keys on the CI to pull up our “002082” course.
- Since we know this will not return a unique value in this situation,
a standard CI
getmethod would actually fail with an error that the
getmethod returned more than one result. You can only use
getif it returns one and only one row in the search record.
- So what we have to do is basically act as if we are “searching” for
a class to get a search result back in code and just choose the
first search result. This is done using the
findmethod and then processing a collection of response objects.
- What I don’t think is documented very well is that the
findmethod actually returns a collection of component interface objects. It is a bit confusing at first. You can loop through the collection, finding the one you want and then execute the
getmethod on one of the items in the collection.
- You may want to re-read this bullet point a few times until it sinks in.
So let’s look at the code for this situation.
&oCrseCatalog.INSTITUTION = "PSUNV"; &oCrseCatalog.CRSE_ID = "002082"; Local ApiObject &oCrseCatalogFindCollection; &oCrseCatalogFindCollection = &oCrseCatalog.find(); If &oCrseCatalogFindCollection.Count = 0 Then /* You need some error here if you always expect the CRSE_ID to be there */ Else /* find() returns a collection of Component interface */ /* objects matching search criteria */ /* set modes again as they do not inherit from find CI */ &oCrseCatalog = &oCrseCatalogFindCollection.item(1); &oCrseCatalog.InteractiveMode = True; &oCrseCatalog.GetHistoryItems = True; &oCrseCatalog.EditHistoryItems = True; If &oCrseCatalog.Get() Then /* TODO - This is your section for */ /* standard processing of the collections and properties */ oCrseCatalog.DESCR = "New Description"; else /* TODO: Error Handling for Get Failure */ End-If; End-If; end-if;
In the code above you see that we first execute the
find method and
capture the result in the
&oCrseCatalogFindCollection variable. In our
situation, we know we can actually take any of the results returned
because we searched by the unique CRSE_ID field. So we execute this
line of code.
&oCrseCatalog = &oCrseCatalogFind.item(1);
This pulls off the first item from the collection and assigns it to an
APIObject variable. The strange thing here is that the item returned in
&oCrseCatalog is a full blown CI object just like this line of code
from the setup section at the top:
&oCrseCatalog = &oSession.GetCompIntfc(CompIntfc.X_CRSE_CATALOG);.
However, there are some subtle differences.
- The properties like
GetHistoryItemsare not inherited and will be the default for CI.
- This points an object which has search results populated.
- You have to execute a
geton one of the items in the collection then work with that item to update the data in the component interface.
Other Uses of the “Find” Method
You can take the example above and use it in other situations as well.
Typically, if you are using CI from within PeopleCode you have full
access to the database to lookup key values direclty in the database
prior to loading a CI for some sort of data entry. So typically, there
is never a need with calling CI within PeopleCode to do a
You will be primarily using
However, if you are using CI from some external system like JAVA, you
can use the above example to use the
Find method in more of a search
scenario. For example, your JAVA application may not know if a certain
key exists in the database. So you may do a partial key search using
find and then processing the result set. If there are zero results
found then you may need to do a
create. If there are more than zero
search results found, you may need to loop through the results and
perform appropriate processing.
Hopefully, this helps you understand the use of the CI
Have a wonderful day!