By | 16 June 2015

An Example of using the CI “Find” Method

The Find method on the component Interface API is poorly documented in the Component Interface Section of PeopleBooks. 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 example.

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 get method would actually fail with an error that the get method returned more than one result. You can only use get if 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 find method and then processing a collection of response objects.
  • What I don’t think is documented very well is that the find method 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 get method 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 InteractiveMode and GetHistoryItems are not inherited and will be the default for CI.
  • This points an object which has search results populated.
  • You have to execute a get on 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 find method. You will be primarily using get and create.

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 find method.

Have a wonderful day!

Do you want to become a CI Expert?

If you want to learn more about developing using Component Interface then check out our CI Training Video.