[SalesForce] How to Query 2 Objects Down Parent to Child SOQL in APEX Class

I'm creating a visualforce related list on the Opportunity record layout. This related list is supposed to show a list of services (object name: QService__c) on the synced quote related to that opportunity.

Here is the class:

public class serviceViewController {

public final Opportunity opp;

public List<Quote> getQServices{get; set;}
public serviceViewController(ApexPages.StandardController controller) {
    this.opp = (Opportunity)controller.getRecord();
    getQServices = [SELECT Id, Name, IsSyncing,
                    (SELECT Id, Name FROM QService__r)
                    FROM Quote
                    WHERE Opportunity__c = :opp.Id AND IsSyncing = true 
                    ];

}}

I'm using a class extension to pull in the filtered data since I need to use a standard controller if I'm going to have this on an opportunity layout.

My thoughts were to originally pull from the quote, and do a downward transversal to the child object (QService__c) of the parent object (Quote). And then on the WHERE statement, pull these fields of the synced quote on the opp. And then display the QService__c fields Id and Name.

I thought this would work because it's referencing the Opportunity and it's going down 1 level from the Quote to the service object (QService__c) but I'm getting this error from the developer console:

    (SELECT Id, Name FROM QService__c)
                          ^

ERROR at Row:2:Column:47
Didn't understand relationship 'QService__c' in FROM part of query call. If you are attempting to use a custom relationship, be sure to append the '__r' after the custom relationship name. Please reference your WSDL or the describe call for the appropriate names.

I don't understand because from what I've been scouring all over online, I'm using the correct reference __r for Parent to Child relationships.

Any help or suggestions on this on why my query isn't working? or if you think I could be doing this in a better way?

And for reference and testing, here is my visualforce code.

<apex:page standardController="Opportunity" extensions="serviceViewController" lightningStyleSheets="true">
<apex:form >
    <apex:pageBlock title="QServices">
        <apex:pageBlockTable value="{!getQServices}" var="qservice">
            <apex:column headerValue="Id" value="{!qservice.Id}"/>
            <apex:column headerValue="Name" value="{!qservice.Name}"/>
            <apex:column headerValue="Is Synced" value="{!qservice.IsSyncing}"/>
        </apex:pageBlockTable>
    </apex:pageBlock>
</apex:form>

Best Answer

This is one of the most confusing aspects of relationship queries in SOQL. The FROM clause in your subquery does not specify the name of the child object. It specifies the name of the relationship, which is configured as part of the lookup or master-detail field on the child object and may or may not look like the child object's actual API name. You can look it up on the detail screen for the relationship field, and make sure to post-fix a custom relationship name with __r.

See the SOQL documentation for more details on the intricacies of relationship queries (plus helpful screenshots).

Related Topic