How to Build a Hierarchical Map using Apex
I was recently working on an integration project where we needed to generate a simple piece of output! I needed a simple hierarchical map of Salesforce objects which can be retrieved from relational queries. Sounds simple enough, right? You couldn’t be farther from reality though. It ended up giving me sleepless nights!
Ticking off the list…
When I started designing, I realized that there are many things that had to be taken into consideration for the design to hold up in the long run. The design needed to be reusable, support ‘n’ levels, support lookup, master-detail relationships and provide for value match for related records. Moreover, the design needed to have the ability to support more than one where clause to retrieve related records, to add child data to the single parent map and give you the flexibility to configure your own keys for the values.
Once I ensured my framework had all of this, it looked something like this:
The objects outlined above had the following key features:
- Query – Query object would hold the queries
- Domain – Domain object would hold a reference to the query to be executed. Some of the key attributes of the Domain object are listed below:
- Query – It contains the reference to the Query object
- Domain Parameters – These are parameters required by the top level domain to execute. For e.g. – the keyword to bind the result set, any input parameter to be provided to the top level query. This can be put in the JSON format.
- Domain Index – This object will hold the reference to the parent and child domain. Some of the key attributes of the Domain Index object are listed below:
- ParentDomain – It contains the reference to the parent Domain ID
- Domain – It contains the reference to the Domain
- BindTo – This field will contain the field name based on which the child data will be bound to the parent
- GroupBy– This field will contain the Param Property Name based on which the child data will be grouped.
- PropertyPool – This object is a pool of all the properties or fields that would be referenced in the queries
- Param Group – This object will be specific to each query to hold the input and output parameters for the query
- Param Properties – This is a junction object between Param Group and Param Properties
Twist in the Tale…
However, the trickier part here was how to build the tree. While retrieving the results was simple enough, all the result sets needed to be merged together to be inserted into the map in the form of the tree defined in the metadata.
At first, I tried building it from top to bottom but unfortunately that didn’t work out. I then found a simpler way to build it using the bottom up approach.
Need of the Hour…
This is the sample hierarchy that is expected
->Account
->Contact
->CustomObject A
->CustomObject B
How I Won the Battle
The approach that I followed is a 6-step process.
- First, I defined Account as the top level domain and Contact as its domain index
- Then I defined CustomObject A as the domain index for Contact and
- CustomObject B as the domain index for Custom Object A
- I went on to define the param properties for each domain and created all the input and output parameters
- I stored all the result sets from each query in a List of Map (String, Object). While storing the result set for the child queries, it’s important to store it grouped by the grouping parameter (GroupBy) defined in the Domain Index.
- Now, I started building the tree by iterating from the second last member in the list going the level up in the hierarchy and based on the GroupBy field keyword, I could club the child with the parent.
Although it looks a bit complicated on the first look, you will notice that everything falls in place as you start writing the code. I have elaborated the architecture within this post and in my next post, I would be including the code snippets that support the same.