function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Justin1Justin1 

Question on Map in Triggers Trailhead

Hello all,

First post here, I am trying to learn Apex and a newbie at this. I am trying to do the following trailhead:

https://trailhead.salesforce.com/trails/force_com_dev_beginner/modules/apex_triggers/units/apex_triggers_intro

In the example, they provide the following code:
// Get the related opportunities for the accounts in this trigger Map<Id,Account> acctsWithOpps = new Map<Id,Account>( [SELECT Id,(SELECT Id FROM Opportunities) FROM Account WHERE Id IN :Trigger.New]);

I don't understand why map is declared of type Account but then the subquery (SELECT Id FROM Opportunities) returns IDs of type opportunities?

Second question:
System.debug('acctsWithOpps.get(a.Id).Opportunities.size()=' + acctsWithOpps.get(a.Id).Opportunities.size());
Since opportunities is a child object to account, why do we use get(a.id).opportunities because I thought the dot notation was to traverse from child to parent?

Appreciate all the help...
J




 
James LoghryJames Loghry
Hi Justin,

In the first code snippet, you're querying Account records.  The opportunities are children of the account records, and essentially are just along for the ride, so to speak.

In fact all of the following variable assignments should work:

sObject a = [SELECT Id,(SELECT Id FROM Opportunities) FROM Account WHERE Id IN :Trigger.New Limit 1];
Account a = [SELECT Id,(SELECT Id FROM Opportunities) FROM Account WHERE Id IN :Trigger.New Limit 1];
List<Account> accounts = [SELECT Id,(SELECT Id FROM Opportunities) FROM Account WHERE Id IN :Trigger.New];
List<sObject> sobjects = [SELECT Id,(SELECT Id FROM Opportunities) FROM Account WHERE Id IN :Trigger.New];
Map<Id,Account> accountMap = new Map<Id,Account>([SELECT Id,(SELECT Id FROM Opportunities) FROM Account WHERE Id IN :Trigger.New]);
Map<Id,sObject> accountMap = new Map<Id,sObject>([SELECT Id,(SELECT Id FROM Opportunities) FROM Account WHERE Id IN :Trigger.New]);

This also plays into your second question. The dot notation applies to both parent and child relationships.  Actually, the dot notation is simply saying "give me the following property of this object", where the property could be a field, a parent relationship, or a list of related child records.

Consider the following example, which would take place with an account hierarchy and opportunities linked to children accounts in the account hierarchy:
 
Map<Id,Account> childrenAccountMap = new Map<Id,Account>([SELECT Id,Account.Name,Name,(SELECT Id FROM Opportunities) FROM Account WHERE Id IN :Trigger.New]);
for(Account child : childrenAccountMap.values()){
    System.debug('Child name: ' + child.Name);
     //Get the parent account and display its name
    System.debug('Parent name: ' + child.Account.Name);

    //Get opportunities pertaining to just current child account
    Map<Id,Opportunity> childOpportunitiesMap = new  Map<Id,Opportunity>(child.Opportunities);
    for(Opportunity opp : childOpportunitiesMap.values()){
        System.debug('Child opportunity Id: ' + opp.Id);
    }
}



In the above example, I'm using the dot notation to get the parent account from the child, as well as the child's opportunities, and displaying a bit of information around each.

Hopefully that helps clarify your question(s).

-  James
 
Justin1Justin1
Appreciate the help, James.
My confusion is that in a map, we store key and a value. In my example above, we declared the map as (id, Account) and then in the query, after the id, we are running a subquery of type Opportunities which will return ids of type Opportunities. This is not making sense to me. Shouldn't the type match with what's returned from the subquery?

Also in your example:
sObject a = [SELECT Id,(SELECT Id FROM Opportunities) FROM Account WHERE Id IN :Trigger.New Limit 1];

You are returning an id and then another id(from opportunities) but which field of the sObject, a, is this getting stored in?

I will defer my 2nd question because just this right now has got my eyes rolling. 
 
James LoghryJames Loghry
Simply put, no.  The returned type matches the top most query. The  sub query is just a portion of the top most query.  Think of it this way, if you're NOT querying any related records, then what would the return type be?    
Justin1Justin1
Apologize for the delayed response. I got pulled into some other stuff. 

User-added image

Given the above query, the result time in the subquery is clearly opportunities and that's the cause of my confusion. If I removed the subquery, off course I end up with Account ids which does match the return type. Hope you get the conundrum I am in...