Expanding relationships - SmartPlant Foundation - IM Update 44 - Customization & Programming - Hexagon

SmartPlant Foundation Customization

Language
English
Product
SmartPlant Foundation
Search by Category
Customization & Programming
SmartPlant Foundation / SDx Version
10

IObject has two methods on it for getting relationships from that object:

Public Function GetEnd1Relationships() As IRelDictionary

Public Function GetEnd2Relationships() As IRelDictionary

Notice that these functions return an IRelDictionary. This is a collection of all the relationships (filtered by End1 or End2 by the method called) on this object. There are several variants of the GetRel method to return a single relation as IRel.

The variants of GetRel should only be used if you are certain that you are crossing a "to one" relationship. If you are not certain or you know that you are crossing a "to many" relationship, then you should use the variants of GetRels.

This variant just accepts the RelDefUID and returns the first instance of that relationship:

Function GetRel(ByVal pstrDefUID As String) As IRel

This variant adds the ExpandRelationSource to allow you to restrict the query to the client cache or go straight to the server. The Auto option allows the client to choose.

Function GetRel(ByVal pstrDefUID As String, ByVal ptypSource As ExpandRelationSource) As IRel

The variants of the GetRels method should be used when crossing "to many" relationships. The first just accepts a RelDefUID to return all instances of that RelDef.

Function GetRels(ByVal pstrDefUID As String) As IRelDictionary

The others are just different combinations of the same parameters.

Function GetRels(ByVal pstrDefUID As String, ByVal ptypSource As ExpandRelationSource) As IRelDictionary

The thing to keep in mind here is that these methods all return instances of relationships, not the objects on the other end of the relationships. To get the objects, you need to call another method on IRel or IRelDictionary. From IRel, you call either the GetEnd1 or GetEnd2 method, each of which return an IObject.

Public Function GetEnd1() As IObject

Public Function GetEnd2() As IObject

From IRelDictionary, you call a variant of GetEnd1s or GetEnd2, each of which return an IObjectDictionary.

Function GetEnd1s() As IObjectDictionary

Function GetEnd2s() As IObjectDictionary

The following two variants allow you to specify a container for the objects. Since the objects will be appended into the container passed in, this may be useful in building up a container of objects from multiple queries or expansions.

Function GetEnd1s(ByVal lobjTarget As IObjectDictionary) As IObjectDictionary

Function GetEnd2s(ByVal lobjTarget As IObjectDictionary) As IObjectDictionary

So, let's take an example and walk through how to use these APIs. Let's say that we have retrieved an SPF method from the ADMIN domain and want to traverse to the Client API related to it. The relationship is this:

You must take care to know on which end of the RelDef your object is defined. Many times you can determine this from the naming convention (as in this case). But many times you cannot. In this case, Method is on End2.

Also, you need to take careful notice of the cardinality of each end of the RelDef. In this case, going from Method to Client API is a "to one" traversal. So, an example of traversing this relationship is like this:

Dim lobjClientAPI As IObject = lobjMethod.GetEnd2Relationships().GetRel("SPFClientAPIMethods").GetEnd1()

The first method call to GetEnd2Relationships returns all the End2 relationships from the method. The second call to GetRel filters that to the single instance of SPFClientAPIMethods, and the final call to GetEnd1 returns the Client API object.

But what if we had the Client API and wanted to traverse to all methods referencing it? We know that we're now working from End1 of the relationships, but the cardinality has changed. We'll now be traversing a "to many" relationship so we need to change to the GetRels methods on IRelDictionary. An example of this is:

Dim lcolMethods As IObjectDictionary = lobjClientAPI.GetEnd1Relationships().GetRels("SPFClientAPIMethods", False).GetEnd2s()

The first call to GetEnd1Relationships returns an IRelDictionary of all relations where the Client API is on End1. The second call to GetRels filters those relationships by the RelDefUID "SPFClientAPIMethods". The third call to GetEnd1s expands to the objects on End2 of each of those relationships. This will return an IObjectDictionary, so now you must iterate through the results.

Let's try another example and string together two relation expansions. Look at the PBSItemCollection RelDef.

This is used to build the plant hierarchy. The first thing to notice here is that the PBSItemCollection is on End2 of this relationship. That means that the parent object is on End2. The second thing to notice is that moving from child to parent is traversing "to many". However, in this example we're going to be navigating from Unit through Area to Plant, and we'll assume that there is only one parent (which is the normal case).

Dim lobjPlant As IObject = lobjUnit.GetEnd1Relationships().GetRel("PBSItemCollection").GetEnd2().GetEnd1Relationships().GetRel("PBSItemCollection").GetEnd2()

From the FunctionalUnit object the first call is to GetEnd1Relationships (because the IPBSItem or child is the End1). The next call filters it down to a single "PBSItemCollection" relationship, and we call GetEnd2 to get the parent. In this case, the parent is a FunctionalArea.

The next call can assumed to be from the FunctionalArea object, and it returns the End1Relationships, which are then filtered to a single "PBSItemCollection" relationship. The GetEnd2 returns the Plant object.

This is a dangerous way of programming because any one of these expansions could return null and would throw an exception.