Coding question asked by Google
Find the top most parent accountId by traversing the account hierarchy
Recursive method
public with sharing class AccountHierachy {
//recursive method to find parentId of top account
private Id topParentId = null;
public Id getParentAccountsFromAccountId(Id accountId){
Id parentId = null;
Account acc = [Select Id, Parent.Id, Parent.Parent.Id, Parent.Parent.Parent.Id, Parent.Parent.Parent.Parent.Id, Parent.Parent.Parent.Parent.Parent.Id
from Account where Id=:accountId][0];
if (acc!=null)
parentId = findParentFromAccountId(acc, parentId);
if (parentId!=null){
topParentId = parentId;
getParentAccountsFromAccountId(parentId);
}
return topParentId;
}
public Id findParentFromAccountId(Account acc, Id parentId){
//level1
if (acc.Parent.Id!=null){
parentId = acc.Parent.Id;
//level2
if (acc.Parent.Parent.Id!=null){
parentId = acc.Parent.Parent.Id;
//level3
if (acc.Parent.Parent.Parent.Id!=null){
parentId = acc.Parent.Parent.Parent.Id;
//level4
if (acc.Parent.Parent.Parent.Parent.Id!=null){
parentId = acc.Parent.Parent.Parent.Id;
//level5
if (acc.Parent.Parent.Parent.Parent.Parent.Id!=null){
parentId = acc.Parent.Parent.Parent.Parent.Parent.Id;
}
}
}
}
}
return parentId;
}
}
Batch class
global class AccountHierachyBatch implements Database.Batchable<sObject>, Database.Stateful {
private static Id nextParentId;
@TestVisible private static Id lastParentId;
private Id parentId;
private Id accountId;
global AccountHierachyBatch(Id accountId){
this.accountId = accountId;
}
String query = 'Select Id, Parent.Id, Parent.Parent.Id, Parent.Parent.Parent.Id, Parent.Parent.Parent.Parent.Id, Parent.Parent.Parent.Parent.Parent.Id from Account';
global Database.QueryLocator start(Database.BatchableContext bc){
query+=' where Id=\''+ accountId + '\'';
return Database.getQueryLocator(query);
}
public void execute(Database.BatchableContext bc, List<Account> accounts){
AccountHierachy accountHierachy = new AccountHierachy();
Account selectedAccount = null;
if (accounts!=null && accounts.size() == 1){
selectedAccount = accounts.get(0);
}
Id parentId = accountHierachy.findParentFromAccountId(selectedAccount, parentId);
if (parentId!=null){
nextParentId = parentId;
} else {
nextParentId = null;
}
}
public void finish(Database.BatchableContext bc){
if (nextParentId!=null){
lastParentId = nextParentId;
Database.executeBatch(new AccountHierachyBatch(lastParentId));
}
}
}
Test class
@isTest public class AccountHierachyTest {
@TestSetup static void setup(){
Account a1 = new Account(Name='a1');
insert a1;
Account a2 = new Account(Name='a2');
a2.ParentId = a1.Id;
insert a2;
Account a3 = new Account(Name='a3');
a3.ParentId = a2.Id;
insert a3;
Account a4 = new Account(Name='a4');
a4.ParentId = a3.Id;
insert a4;
Account a5 = new Account(Name='a5');
a5.ParentId = a4.Id;
insert a5;
Account a6 = new Account(Name='a6');
a6.ParentId = a5.Id;
insert a6;
Account a7 = new Account(Name='a7');
a7.ParentId = a6.Id;
insert a7;
Account a8 = new Account(Name='a8');
a8.ParentId = a7.Id;
insert a8;
Account a9 = new Account(Name='a9');
a9.ParentId = a8.Id;
insert a9;
Account a10 = new Account(Name='a10');
a10.ParentId = a9.Id;
insert a10;
}
@isTest static void testFindParentFromAccountId(){
Account pAccount = [Select Id from Account where Name='a10'][0];
Id topParentId = null;
Test.startTest();
AccountHierachy ah = new AccountHierachy();
topParentId = ah.getParentAccountsFromAccountId(pAccount.Id);
Test.stopTest();
Account topParent = [Select Id from Account where Name='a1'][0];
System.assertEquals(topParentId, topParent.Id);
}
@isTest static void testFindParentFromAccountIdBatch(){
Account pAccount = [Select Id from Account where Name='a10'][0];
Test.startTest();
AccountHierachyBatch ah = new AccountHierachyBatch(pAccount.Id);
Database.executeBatch(ah);
Test.stopTest();
Account topParent = [Select Id from Account where Name='a1'][0];
System.assertEquals(AccountHierachyBatch.lastParentId, topParent.Id);
}
}
Thank you for the awesome article. I’ve come up with a solution with Queueable.
public class AccountHierachyQueueable implements Queueable{
public static Id topParentId;
public Id accountId;
public AccountHierachyQueueable(Id accountId) {
this.accountId=accountId;
}
public void execute(QueueableContext con){
Account acc = [SELECT Parent.Parent.Parent.Parent.Parent.Id,
Parent.Parent.Parent.Parent.Id, Parent.Parent.Parent.Id,Parent.Parent.Id,Parent.Id FROM Account where Id=:accountId];
Id higher5 = acc.Parent?.Parent?.Parent?.Parent?.Parent?.Id;
if(higher5!=null){
System.enqueueJob(new AccountHierachyQueueable(higher5));
}else{
Account current = acc;
while(current.parent!=null){
current = current.parent;
}
topParentId = current.Id;
}
}
}