0

I am trying to get record type id's from sub query under map, when I am iterating over map values I am getting "A non foreign key field cannot be referenced in a path expression" error

My requirement is to throw error if more than one record created per record type, so trying to capture Record type id and account Id.

public static void throwerror(list<sObject> dataset){
        List<Plan__c > Plans = (List<Plan__c >)dataset;
        Set<Id> accIds = new Set<Id>();
        for(Plan__c ap:plans){
            if(ap.Account__c != null)
            accIds.add(ap.Account__c); 
        }
        Map<Id, Account> accMap = new  Map<Id, Account>([Select id , (Select Id,RecordType.Name,RecordTypeId From Plan__r) From Account Where Id IN :accIds ]);
        map<Id,String> keymap = new map<Id,String>();
         for(Account acc : accMap.values()){
             keymap.put(acc.Id,acc.Plan__r.RecordTypeId);// Error : A non foreign key field cannot be referenced in a path expression: Plan__r
         }
         system.debug('--->>>'+keymap);
         for(Plan__c ap:plans){
                        //here I want to include condition to check if accid and plan record id exists
            if(accMap.containsKey(ap.Account__c) && !accMap.get(ap.Account__c).Plan__r.isEmpty()){
                ap.addError('Only one plan is permitted per Record type');
            }
        }
    }

1 Answer 1

1

Assuming that your query is correct, the issue here is that acct.Plan__r isn't a single SObject instance.

Parent-child subqueries always return an embedded List<SObject> in the parent object, even if there is only one (or even zero) child records.

When you're working with a small number of child records, directly accessing the embedded list of child records can work, but the safe method to do access the child records is to use a nested loop.

Aside from that, I'd think that using a Map<Id, Set<Id>> would be a better choice for determining if there's already a record for a given account id - plan record type id pair. Using a Map<Id, String> limits you to storing a single record type id per account.

Map<Id, Set<Id>> acctIdToUsedRecTypeIds = new Map<Id, Set<Id>>();
for(Account acc : accMap.values()){
    // General map population pattern:
    // If we don't have the key in the map, put into the map so we can use it later
    //   in the loop without additional checks
    if(!acctIdToUsedRecTypeIds.containsKey(acc.Id)){
        acctIdToUsedRecTypeIds.put(acc.Id, new Set<Id>());
    }

    // Safest option is to use a nested loop to access child records
    for(Plan__c acctPlan :acc.Plan__r){
        acctIdToUsedRecTypeIds.get(acc.Id).add(accPlan.RecordTypeId);
    }
}

Your check a little later on would then be acctIdToUsedRecTypeIds.get(ap.Account__c).contains(ap.RecordTypeId);

1
  • Thanks so much!
    – ANAP
    Commented Dec 8, 2021 at 15:04

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .