When I first became a rule author, one of the initial challenges I encountered was making nested comparisons that compared one of the fields of one member of a collection against that field for the other members in the collection. To illustrate this, let’s look at the scenario illustrated in the screenshot below.
For this example, we need a rule to identify twins in the Children collection, where a twin is defined as a Child that has the same Date of Birth as another member in the Children collection and the ID is different. Visually, we can see that Bob and Sally would meet this condition but Mark would not.
When we try to author this rule, we may run into difficulty. We should be able to use the Any Members Exist template (which is simply a Count function where the results are greater than zero) against the collection at the parent level.
The trouble occurs when creating the filter criteria. It may be tempting to author the rule as shown in the screenshot below, where the “Date Of Birth” is equal to “Date Of Birth” and the “ID is not equal to ID”. Unfortunately, this will fail to do what we need it to do because the filter criteria compares those fields against themselves.
We need our filter criteria to check the Date Of Birth and ID’s in our aggregate function against those fields in this instance. It is as if we need to compare the field from the aggregate expression against the values of those fields in the current context of the rule. Speaking of which….
Current Context
There is a syntax function called, “Current Context” (also available as “Current”) that provides the exact functionality we need to identify the twins in our collection.
Current Context is used to access a field in the context of the current expression, which may have the same name as a field in the context of the collection member when authoring an aggregate function. This is not to be confused with the “OuterContext” function, which is used to access a field of the same name outside the context of an aggregate expression. OuterContext may be useful if you are nested within multiple aggregate expressions.
If we convert our rule into syntax mode, we can add our Current Context functions as shown below.
When we do this, the rule works as intended and correctly identifies the twins in our collection.
We now know what function to use to handle scenarios comparing one member in our collection against its siblings within the collection. We now need a good pattern so we can use this in Business Language.
Creating a Reusable Template
The Current and CurrentContext function are only available in syntax mode and these functions do not have a counterpart in business language. We could use the Expression Designer to use the CurrentContext function in a business language template, but it may look a little awkward. So the next question that arises is how to use this function within business language and reuse it if we need to make a similar match later. For this, we will look at creating an expression template in our vocabulary.
One slight complication is that our vocabulary expression templates must return a data type and our Current Context function will return the data type of the field or expression contained therein. Also, we want to reuse this template and without creating a separate template for each data type.
One solution would be to make the statement into a Boolean expression so it can be used in the criteria of any aggregate expression. To further increase the utility of our vocabulary expression, we can set the context of our vocabulary template at the rule application level. This will allow it to be used throughout the rule application. We can use placeholders for each of our comparison fields and allow that place holder to accept any of the .NET primitive data types as shown in the example below.
Next, it is a simple matter of completing the rest of the vocabulary template as seen in the example below.
Now we can replace the criteria in our Language Rule. Note that we can use the “Is False” expression to use our vocabulary template both for a positive and a negative match.
Upon testing, we can see the vocabulary template works.
In conclusion, with a little planning, these formerly complex nested comparisons in aggregate functions can be streamlined to easily simplify otherwise complex expressions.