Salesforce SOQL doesn’t have traditional joins, instead, there are 2 different types of relationship queries: Parent-to-Child and Child-to-Parent. Child-to-Parent SOQL queries is Salesforce’s way to join a list of child-related records with a parent record. In order to obtain the list of child records and their data the SOQL query must look something similar to:
SELECT Name, ( SELECT LastName FROM Contacts ) FROM Account
In the above example, we get a list of all contacts that are associated with each Account record. As you can see the Contact object is referenced using the object’s child relationship name of Contacts (plural). In a custom object, the relationship name is created during the lookup field creation. As an example create a custom object such as; Opp Child, with a developer name of Opp_Child__c. Next, create a custom lookup or master-detail field Opportunity__c with a relationship name of Opp_Children:
Resulting in a Child-to-Parent using the child relationship name with __r appended and not the object name such as:
Select Id, (Select Id from Opp_Children__r) from Opportunity
Going to the lookup field works for custom fields and some standard fields where you can view the field in object manager. However what about standard fields that aren’t in object manager. What if you wanted to query the Opportunity and OpportunityFeed. The standard naming convention of other objects would make me think it would be OpportunityFeeds however that is not correct and provides an error.
So how do we find the correct child relationship name? We can use the getDescribe() method with the getChildRelationship() method to get the object child relationship name with the ChildRelationship class. In the following custom class we are dynamically creating an sObject based on the name of the of that object and the name of the child object we are trying to find the relationship name for:
public static String getChildRelationshipName(String parentsObj, String childsObj) {
//Create sobject Instance
sObject dynamicObj = (SObject)Type.forName(parentsObj).newInstance();
//get the type token
SObjectType sObjType = dynamicObj.getSObjectType();
//get describe
DescribeSobjectResult sObjDescribe = sObjType.getDescribe();
//loop through children
for(Schema.ChildRelationship rels :sObjDescribe.getChildRelationships()){
//find the child
if(String.ValueOf(rels.getChildSObject()) == childsObj){
return rels.getRelationshipName();
}
}
return null;
}
Next just call that method (I placed it in a ChildRelationshipService class):
system.debug(ChildRelationshipService.getChildRelationshipName('Opportunity', 'OpportunityFeed'));
Can we can see the OpportunityFeed relationship name is actually Feeds. Next we can run the following:
Select Id, (Select Id, Title, Body from Feeds) from Opportunity
If you would like to return a map of the ChildRelationships for the object you can use the following:
public static Map<String, ChildRelationship> getChildRelationshipMap(String parentsObj){
Map<String, ChildRelationship> sObjChildRelationshipName = new Map<String, ChildRelationship>();
//Create sobject Instance
sObject dynamicObj = (SObject)Type.forName(parentsObj).newInstance();
//get the type token
SObjectType sObjType = dynamicObj.getSObjectType();
//get describe
DescribeSobjectResult sObjDescribe = sObjType.getDescribe();
//loop through children
for(Schema.ChildRelationship rels :sObjDescribe.getChildRelationships()){
//put the child in map
sObjChildRelationshipName.put(String.ValueOf(rels.getChildSObject()), rels);
}
return sObjChildRelationshipName;
}
If you would like use the map instead you can run the following:
system.debug(ChildRelationshipService.getChildRelationshipMap('Opportunity').get('OpportunityFeed').getRelationshipName());
Here is the Github repo.
Checkout My New Course:
Crush It As A Salesforce Developer: Mastering Apex
Test Your Knowledge:
Try the new Salesforce Developer Quiz