Navigating relationships in life may be hard but doesn't have to between custom sObjects
. The SOQL documentation has several examples with standard sObjects. Custom sObjects have some differences – mostly syntactical. We will illustrate that using a few sample SOQL queries.
We will use the example from the Developer Guide The object model is reproduced below (click on the pictures to enlarge them).
When you insert a relationship field on an sObject (either a lookup or master-detail) to another object, the other object is called the parent sObject. So Location is the parent of Position in the object model shown. The cardinality from parent to child is one to many, so a single location can have many positions associated with it. The child object will have both the ID of the related parent record as well as a relationship field to access the fields in the related record.
CHILD to PARENT
Say we want to find the location id and city associated with a given position. The query would look like this
SELECT Location__r.Id, Location__r.City__c FROM Position__c p WHERE p.Name='POS-00001'
What is Location__r? It is the name of the relationship field from Position to Location. You can find this on the field definition screen – click on the picture on the left. Note that you have to append a __r to the name on the screen. You can traverse multiple levels of child parent relationship in this manner. For example, we can retrieve the field values of a location record from Job Application by traversing from Job Application to Position to Location as shown below.
SELECT Position__r.Location__r.Id, Position__r.Location__r.City__c FROM Job_Application__c ja WHERE ja.Name = 'JA-00001'
PARENT to CHILD
Remember that the cardinality of this relationship is one to many so we should expect to retrieve back a collection of child objects. The child objects are retrieved using a sub-query.
Location__c[] locations = [SELECT l.Name, l.City__c, (SELECT Name, Department__c FROM Positions__r) FROM Location__c l ]
Positions__r is the name of the child relationship. We find it on the field definition screen as before – click on the picture to the right. Notice the plural (by default) and appending __r (as before).
Now we can iterate over the collection of locations as well as the associated child positions for each location in a loop.
for( Location__c l : locations ){ // position object associated with each location for( Position__c p : l.positions__r){ System.debug('*****>>>>>> Name = ' +p.Name +' Department = ' +p.Department__c ) ; }}![]()
The previous query did an outer join, so it would retrieve locations even if there were no associated positions. To only retrieve locations for which there are associated positions, we would need to do a semi-join as shown below.
Location__c[] locations = [SELECT Id, Name, City__c, (SELECT Id, Name, Department__c FROM Positions__r) FROM Location__c WHERE Id IN (SELECT Location__c from Position__c) ] ;
CHANGING THE ASSOCIATED RECORD Notice the query after IN in the previous example. Location__c contains the ID of the related Location record. We can use this field to change the related record as in the example below. // Retrieve a position record with the ID of the associated location recordPosition__c p = [SELECT Location__c, Location__r.Name FROM Position__c WHERE Location__r.Name='HQ' LIMIT 1]// Retrieve the Id of the record we want to point it toLocation__c loc = [ select Id from Location__c where Name='Reston' ] ;//change it and update the databasep.location__c = loc.Id ;update p ;The position now points to the Reston location.
