1

I am trying to get the highest level of parent account in an Account Hierarchy in Salesforce via Apex and SOQL. I want to create and MAP<Id, Set<Account>> hierarchy in my Apex class to where the highest parent account's Id is the Id in the Map while all the child accounts (or at any level) are in the Set.

I have written the following recursive function to do this but I can't get all the child Accounts in there for the top most parent account.

public class AccountsHierarchy{

    public Map<Id, Account> allChildAccounts {get; private set;}
    private Map<String, Set<Account>> parentAccountMap {get; set;}
    private List<Account> childAccounts {get; set;}


    public AccountsHierarchy(){

        allChildAccounts = new Map<Id, Account>([
                SELECT Id, ParentId, Parent.ParentId
                FROM Account
                WHERE ParentId != NULL
        ]);
        childAccounts = new List<Account>();
        System.debug(allChildAccounts);
        parentAccountMap = getParentAccountMap();
        System.debug(parentAccountMap);

    }

    private String getParentAccountId(String childAccountId){

        Account localAccount = allChildAccounts.get(childAccountId);
        if(localAccount.Parent.ParentId != null) {

            childAccounts.add(localAccount);
            return getParentAccountId(localAccount.ParentId);

        }else
            return localAccount.ParentId;

    }

    public Map<String, Set<Account>> getParentAccountMap(){

        Map<String, Set<Account>> parentAccounts = new Map<String, Set<Account>>();
        for(String childAccountId:allChildAccounts.keySet()){

            //childAccounts.clear();

            String parentAccountId = getParentAccountId(childAccountId);

            if(parentAccountId != null){

                if(parentAccounts.containsKey(parentAccountId)){
                    Set<Account> childAccountsFromMap = parentAccounts.get(parentAccountId);
                    childAccountsFromMap.addAll(childAccounts);
                    parentAccounts.remove(parentAccountId);
                    parentAccounts.put(parentAccountId, childAccountsFromMap);
                } else {
                    parentAccounts.put(parentAccountId, new Set<Account>(childAccounts));
                }
            }
        }

        return parentAccounts;

    }
}
  • Which child accounts are missing? Is it all accounts from a specific level in the hierarchy? – David Cheng May 25 at 5:48
  • All I get are the child accounts at first level. I want to look for all the child accounts from any level in the hierarchy. – Anas Rashid Jun 6 at 11:34
1

I am working on a similar issue I found alot of help and a solution to this using the following website

https://jdspaceit.wordpress.com/2016/01/13/traversing-through-an-accounts-hierarchy-in-apex/

    //find highest parent account from a child
public id findTopLevelParent(account a) {
    Boolean isTopLevelAccount = false;
    account acct = new account();
    id currAcctId = a.id;

    while (!isTopLevelAccount) {

        acct = [select Id, ParentId From Account where Id = :currAcctId limit 1];
        if (acct.ParentID != null) {
            currAcctId = acct.ParentID;
        } else {
            isTopLevelAccount = true;
        }
    }

    return currAcctId;   
}

From that website I Got this piece of code working.

Update: As for the Map part, heres the link to the flushed out method from that link I shared earlier.

I do not know if this is the best solution, So definetly open to critique

  • Do you think it is the best way to do this? I have the possible data set of 10,000 Accounts and since the query is in the loop, this will definitely fail at some point due to Governor limits. – Anas Rashid Jun 18 at 14:44
  • Also the point is not just get the Top Level Parent but also to create a Map using the Parent Id with the Set of Child Accounts . – Anas Rashid Jun 18 at 14:48
  • @AnasRashid yeah it definitely will flirt the line of governor limits haha. I Updated my post to include my other thread that is on the same topic. That method works but its definitely resource hog. I am looking for better ways to accomplish this as well – Ryan Sherry Jun 18 at 14:54
0

The best approach to this would be, in my opinion, to create a hidden field to store the Id of the account on the top of the hierarchy, and fill it with a trigger, process or workflow rule.

Scenario 1:

  1. Top account is created
  2. Child account is created, but parent account is not related yet.
  3. User remembers that the accounts are related, and fills the "parent account" field.
  4. Have the system update the "account on top of the hierarchy" field with either the value of the same field on the parent record (if it isn't blank) or fill it with the parent record's Id.

Scenario 2:

  1. Top account and child account are created.
  2. User creates a third account that will now act as the parent for the other two.
  3. User fills the "parent account" on the old parent account record with the new top account created.
  4. Have the system update the "account on top of the hierarchy" field on the child records, if the account is the new parent or not (checking the same field, again).

Scenario 3:

  1. Top account, middle account and bottom account are created.
  2. User creates another account that will sit between two of those.
  3. User fills the "parent account" of the new account with the referente of any of the accounts currently in the database.
  4. If the account selected as parent is the top one, check if the "account on top of the hierarchy" field of the parent record is empty. If it is not, then the created account should copy the parent's account field. If it is empty, then the parent account is the top account, and the system should copy the account Id instead.

These should cover the most common scenarios, I believe. That way you will not have to worry about hitting governor limits when searching for the account on top.

It might be a good thing to do a little research if there is such situation where multiple accounts are linked through the ParentId field. If there aren't that many levels, then you'll probably be fine using the query inside the loop as an exception, because it is indeed simpler than doing all this. But if you don't know how many accounts can be nested or the business requires that the accounts are nested, then it might be a good idea to invest some time in this kind of solution.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.