Salesforce coding lessons for the 99%
Finally, Apex tutorials for point-and-click admins! Written by a self-taught Google engineer.
  • Beginner Tutorials
    • Apex
    • Certifications
    • Career Info
    • Technical Architect
    • Visualforce
    • Videos
  • Apex Academy
  • Success Stories
  • About Me
  • Misc
    • Mailbag
    • Challenges
    • Links
    • Login to my Org
Follow @dvdkliuor SUBSCRIBE!

Dot notation – navigating relationships and using methods

October 5, 2013

Preface – This post is part of the Core Apex Tools series.

I still remember the exact moment I fell in love with coding. It happened when I first discovered dot notation. I hope you too can have this joyful moment with Apex some time!

If you’ve ever made validation rules, workflows, or formula fields, chances are you’ve already used dot notation in your career. Dot notation simply lets you traverse objects through relationships and fields:

Decimal companyRev = myContact.Account.Revenue; User friendCreator = myContact.Best_Friend__r.CreatedBy;

The beautiful thing about dot notation in Apex is that there are no restrictions! You can traverse as many relationships as you like and in any direction! There’s nothing more frustrating than building a workflow rule only to find that certain relationships can’t be traversed!

Here’s an example of traversing downwards using dot notation. This isn’t possible without Apex!

List<Opportunity> opps = myContact.Account.Opportunities;

The final use of dot notation is that you can call an object’s instance methods:

Integer numOpps = opps.size(); // A List instance method! String iLoveCaps = myContact.FirstName.capitalize(); // This is a String instance method. The result is DAVID

You can find the instance methods of any object in Salesforce by Googling
Salesforce << Object Name >> methods. We used List methods and String methods in this example.

Very soon you’ll be creating your own instance methods!

Next post: Loops – FOR and FOREACH loops!

56 Comments
Stevie
September 3, 2018 @ 8:19 pm

I am struggling to understand.
public static List getclientSessions(Id recordId){
return [SELECT Id, Name, Type_Event__c, (Select Id, Content__c From Documents__r) from Client_Sessions__c];
}

The query is working. But how do you actually reference it in a component.
for example:

{!cs.Name}
{!cs.Documents__r.Content__c}

What am I doing wrong?

Reply
Rahul
October 12, 2017 @ 4:27 am

Dear David Sir,
How will this statement execute in Developer Console – Anonymous window :-

List opps = myContact.Account.Opportunities;

Please explain by giving some example..

Thanks

Reply
Sumit Datta
July 13, 2017 @ 11:03 pm

Hi David

Thank you very much for such a fantastic work, that you are doing for the beginners. Your tutorials are really descriptive and easy to understand.

I have a question, I am trying to create Visualforce element on click of a button. But everytime I do I am getting an error that page block is not serializable.

What I want to do is to add another apex input text on the visualforce page on click of a button.

I have written some code regarding the same, but not sure to paste it here or not.

Looking forward for some stuff on Dynamic Apex and Dynamic Visualforce component.

Reply
Prabhu
June 10, 2017 @ 3:56 am

my test class:-

@isTest
public class Loops {
static testMethod void testtrig () {
Contact c = New Contact();
c.FirstName = ‘Dream’;
c.LastName = ‘world’;
}

Reply
    Khushboo Vaidya
    August 16, 2018 @ 12:45 am

    DML Statement is missing in your code.

    Add this statement at last:
    insert c;

    and you coverage will rise to 100% :)

    Reply
Prabhu
June 10, 2017 @ 3:55 am

Hi David,

When I am testing the below code, not finding any code coverage over the trigger. Please help me on this.
trigger Lop on Contact (after insert) {
for (Integer i = 0; i < 5; i++) {
// Create five new imaginary friends!
Contact friend = new Contact();
friend.FirstName = 'Kate';
friend.LastName = 'Upton #' + i;
insert friend;

Reply
    David Liu
    June 12, 2017 @ 10:14 pm

    Try asking the official developer forums!

    Reply
      Khushboo Vaidya
      August 16, 2018 @ 12:46 am

      DML Statement is missing in your code.

      Add this statement at last:
      insert c;

      and you coverage will rise to 100% :)

      Reply
Akhil
February 12, 2015 @ 12:54 pm

Hi David,

I am following you tutorials and you are doing awesome work to bring everything in one place. In my work plaece I came across a problem with trigger. I could not write a trigger to update the salesforce 1 checkbox based on user profile. Could you please help me out. I simply can not find the API name for SF1 to use in trigger.

Reply
    David Liu
    February 12, 2015 @ 6:27 pm

    It might not be on the User object!
    https://www.salesforce.com/developer/docs/api/Content/sforce_api_objects_user.htm

    Reply
      Anonymous
      March 10, 2015 @ 9:04 am

      I found it. It is on User object with API name of UserPreferencesHideS1BrowserUI.

      Reply
Mark
October 28, 2014 @ 7:48 pm

Hey David,

Have a question for you…

I’m trying to write a trigger that would roll up the number of contacts that are Primary Liaisons for each account in my org to a new Account field… My trigger successfully saved the below in the Sandbox, but when I try to test it, it is not updating the new field on the Account… Please help, thanks!

trigger primaryLiaisonCount on Account (before update, after update, before insert, after insert) {

//a1 each Account that goes through the trigger
for (Account a1: trigger.new){

//c1 = Amount of Primary Liaisons in each Accounts
decimal c1=[SELECT count() FROM Contact Where AccountID =:a1.ID and Primary_Liaison__c != null];

c1 = a1.Primary_Liaisons__c;
update a1;

}
}

Reply
    David Liu
    October 28, 2014 @ 8:56 pm

    Looks like you switched this line:
    c1 = a1.Primary_Liaisons__c;

    It should be:
    a1.Primary_Liaisons__c = c1;

    Give it a shot!
    David

    Reply
      Mark
      October 28, 2014 @ 9:34 pm

      Thanks so much for your prompt response! You’re so flipping fast!

      Unfortunately… The same thing is still happening… The count() of Contacts that has Primary Liaison not empty is still not populating onto the Account record after I made the switch as you have suggested :(

      Mark

      Reply
        David Liu
        October 28, 2014 @ 9:58 pm

        Here are a few other things:

        1. Take out both “after” events in the beginning of your trigger
        2. Remove the “update a1” line at the end (not needed in before triggers)
        3. Are you sure your trigger saves?!

        If all the above fails, try posting in the SFDC99 forums!
        https://www.sfdc99.com/forums/forum/beginning-apex/

        David

        Reply
      Mark
      October 29, 2014 @ 8:45 am

      I noticed what I did wrong… I started on the wrong object!!! Silly me…

      Here’s the correct code, and now it’s working like a boss!!! Thanks so much David!

      trigger primaryLiaisonCount2 on Contact(after update, after insert, before update, before insert) {

      //c1 each Contact that goes through the trigger
      for (Contact c1: trigger.new){

      //amount1 = Amount of Primary Liaisons in each Accounts
      decimal amount1=[SELECT count() FROM Contact WHERE AccountID =:c1.AccountID AND Primary_Liaison__c != null];
      //Account Record Type = ‘Client’
      LIST acc1=[SELECT ID FROM Account WHERE recordtypeID =’012000000000j8S’];

      for (Account acc2:acc1){
      acc2.Primary_Liaisons__c = amount1;
      upsert acc2;

      }
      }
      }

      Reply
Sriharsha
October 13, 2014 @ 2:27 pm

Hi David,

Quick question.

I wrote a trigger to update the phone number of all contacts when an account is updated. The traversal a1.Contacts however does not seem to work. When I replaced the same with an SOQL query it worked like a charm. Any thoughts?

trigger UpdateAccountContacts2 on Account (after update) {
for(Account a1: Trigger.new)
{

List con1= [select id,AccountId from Contact where AccountId=:a1.ID];
// a1.Contacts;

for(Contact c1:con1)
{
c1.Phone=’9887′;
Update c1;
}

}
}

Reply
    David Liu
    October 13, 2014 @ 9:22 pm

    a1.Contacts isn’t in scope of the trigger since it’s technically another object. Need to use SOQL like you did!

    Reply
Mark S
September 2, 2014 @ 2:35 pm

When using dot notation to traverse downward, is this considered a query? Following best practice, I wouldn’t put a SOQL query inside a loop, but would it be fine to use dot notation like the code snippet you included inside a FOR loop?

List opps = myContact.Account.Opportunities;

Thanks!

Reply
    David Liu
    September 2, 2014 @ 8:30 pm

    You’d have to query for it first (outside a loop), then traverse downward. The traversal itself wouldn’t be a query!

    Reply
      Mark S
      September 3, 2014 @ 6:17 am

      Ahh now it’s all making sense. Thanks!

      Reply
      Reshmi
      December 9, 2014 @ 9:02 am

      Hi David,

      Could you please provide an example for the above concept. ie, Query First and then traversing downwards.

      While writing a test class, i tried to update an Parent field (Like, updating Account Field in Opportunity), to invoke a trigger . But its not happening. What could be the reason.? Thanks Very Much in Advance :)

      Reply
        David Liu
        December 9, 2014 @ 6:44 pm

        Here’s one!

        List accs = [SELECT Name, (SELECT Amount, StageName FROM Opportunities) FROM Account];
        for (Account a : accs) {
          for (Opportunity o : a.Opportunities) {
            System.debug('This opp is worth ' + o.Amount + ' dollars.');
          }
        }

        Reply
chitral
August 9, 2014 @ 3:41 am

Decimal companyRev = myContact.Account.Revenue;

myContact holds what ??
if its resutt of soql query(list) then what are we doing in this statement ,what is the result

Decimal companyRev = myContact.Account.Revenue;

Reply
    David Liu
    August 10, 2014 @ 4:06 pm

    Assume myContact is the result of a prior SOQL query on the Contact object!

    Reply
saikiran
July 15, 2014 @ 3:41 pm

Hello David,
I’ve been following all your tutorials and frankly speaking they are just making me get rid of my so called fear about coding.
would you pleaase lemme know where you got “mycontacts ” from.

Thankyou in advance

Reply
    David Liu
    July 15, 2014 @ 10:06 pm

    Thanks!

    You can just assume that myContact was the result of a SOQL query (check out Chapter 2 to learn more)!

    Reply
Tan
June 25, 2014 @ 5:02 am

David,
User friendCreator = myContact.Best_Friend__r.CreatedBy;
FriendCreator is of which type here? I didn’t get this statement.could you please explain me.

Decimal companyRev = myContact.Account.Revenue;
In the above statement companyRev is a variable of type Decimal.so Revenue contains decimals values.

List opps = myContact.Account.Opportunities;

here “opps” contains collection of datatypes from opportunities right?

Reply
    Viru
    June 26, 2014 @ 11:47 pm

    Hey Tan !
    1. FriendCreator is ‘ User ‘ type.
    CreatedBy field is lookup field which lookup to User object. That’s why we hold it on a User type of variable.

    2. David i think that’s AnnualRevenue (the name of field in account object). So, this is a currency type and currency fields are automatically assigned the type Decimal. That’s why we use a decimal type variable.

    3. Account is a parent object of Opportunity. it have a one-to-many relationship that means an Account have a many opportunities so when we retrieve the opportunity record from an account, it returns a List of opportunities.

    Viru (-;

    Reply
      David Liu
      June 28, 2014 @ 11:25 am

      Thank you Viru, great advice!!! (=

      Reply
        Viru
        June 29, 2014 @ 11:42 pm

        My Pleasure David ! (-;

        Reply
Bruce Frager
June 12, 2014 @ 3:17 pm

David,
Excellent post & quiz explaining this rather challenging topic.
Regarding your comment “The beautiful thing about dot notation in Apex is that there are no restrictions! You can traverse as many relationships as you like and in any direction!” could you please clarify what I have seen elsewhere. Documented limitations of relationship querying can be seen at http://www.salesforce.com/us/developer/docs/soql_sosl/Content/sforce_api_calls_soql_relationships.htm#i1422435.
This specifies limits on the number allowed with only 5 levels ‘downward’ in a parent-to-child relationship and 1 level ‘upward’ in a child-to-parent relationship query. Since your post is not dealing with SOQL, it is possible that these limitations don’t exist for other references in Apex code.
Thanks for ALL you do !

Reply
    David Liu
    June 12, 2014 @ 10:59 pm

    Hahaha another great observation Bruce!

    SOQL does limit the number of relationships but it’s sufficient for 99% of your needs. In the case where it’s not, you simply do an additional SOQL query!

    So the asterisk (*) is that you can only traverse unlimited relationships if you already have the values queried by SOQL!

    Reply
Tom B.
June 10, 2014 @ 2:09 pm

David — I remember when I first fell in love with coding was back in the day of Radio Shacks “Tandy Color Computer” and I typed PRINT “Hello Tom!” and when I hit the enter key on the screen…Hello Tom! I was hooked! That is when I began to teach myself to program and started like self-driven entrepreneur for the various departments (manufacturing) and one of the apps got noticed by IT and that’s when I made the transition from Electrician/Electronic Technician to programmer/Analysis!

Reply
    David Liu
    June 10, 2014 @ 6:36 pm

    Holy cow this is a wonderful story!!!!

    Want to write a post about it on this site? =)

    David
    dvdkliu+sfdc99@gmail.com

    Reply
      Tom B
      June 11, 2014 @ 5:22 am

      Sorry David — didn’t mean to talk about myself — your opening sentence on this page took me back to my time! :)

      Reply
        David Liu
        June 11, 2014 @ 5:16 pm

        hahaha not even kidding about the guest post thing, let me know if you want to do one! No pressure, only if you enjoy telling the story!

        Reply
          Tom B
          June 11, 2014 @ 6:19 pm

          Oh, ok, sure, just let me know the next steps.

          Reply
            David Liu
            June 11, 2014 @ 10:09 pm

            Email sent!

            Reply
    Chuck
    November 29, 2014 @ 3:53 pm

    Wow, I remember trying to correct (in vain) the page formatting on paper I was writing in college using a ‘word processor’ on a TRS-80 with dual 8″ floppy drives. Painful. Can also remember accidentally dropping a large box of punch cards (IBM 360) while walking across campus to submit my ‘job’ at the computer center. And I wish I had kept for sentimental value a few of those yellow rolls of Teletype punch tape that contained all my Basic code. And finally, played my first ‘video game’ called “Asteroid’ on a green terminal powered by a DEC PDP-11 which occupied a 19” rack mount rolling cabinet about 5′ high. How things have changed!

    Reply
S Patrick
May 21, 2014 @ 8:19 am

Awesome work dude. very helpful……………

Reply
Akers
May 19, 2014 @ 11:10 am

Hi David,

I want to traverse 3 level from Account into Opportunity into Opportunity Line Items. How can I do that? I need the records from Opportunity Line Items in order to map them to another object. The problem is, my soql query should be at Account level based.

Reply
    David Liu
    May 19, 2014 @ 7:03 pm

    Try this:

    1. Get a Set of all Account IDs necessary
    2. Do a SOQL query on Opportunities (with a nested SOQL for the line items) and filter where the opp’s Account ID is in the Set in step 1

    Reply
    Akers
    May 20, 2014 @ 12:58 am

    Awesome It worked.. Thank you so much David. You Rock!

    Reply
      David Liu
      May 20, 2014 @ 8:16 am

      ^_^

      Reply
Ian
March 2, 2014 @ 2:37 pm

David, your site is great! I’m glad I stumbled across it. The posts are concise, readable, and high quality. Your responsiveness is commendable. Quick note: the links to the list and string methods pages are broken. Looks like SFDC moved the pages to new URLs. :o Thanks!

Reply
    David Liu
    March 2, 2014 @ 4:01 pm

    Thank you Ian, tell your friends!

    Links are now updated!

    Reply
Fareena
February 25, 2014 @ 6:36 am

Dear David
I am really thankful to you for making such an informative site. I have a phobia of coding but I am hoping to learn some Apex code necessary to be a salesforce administrator.

Many thanks
May God bless you.
Far.

Reply
    David Liu
    February 25, 2014 @ 7:22 pm

    Once you write your first few triggers you’ll wonder why you were ever scared in the first place! You can do it!

    David

    Reply
Amit
February 18, 2014 @ 3:42 am

Hi David,

Can you please define myContact variable in above examples?
Sorry, I know this is silly question but I need to this to clear myself.

Thank,
Amit

Reply
    David Liu
    February 18, 2014 @ 8:04 pm

    No problem! It would go something like this:

    myContact would be a Contact record like this:
    Contact myContact = new Contact();

    At some point, myContact’s accounts and that account’s opportunities will have to be queried beforehand! Note that this scenario is actually extremely rare and only meant to be used as a reference!

    David

    Reply
      Swathi
      May 23, 2014 @ 11:53 am

      David ,

      Quick question ..
      From what you have explained previously , Contact to Account is upward relationship , Account to Opportunity will be a downward relationship .Right?
      In that case
      List opps = myContact.Account.Opportunities; is not completely a downward traversing example .Isn’t it?

      Reply
        David Liu
        May 24, 2014 @ 12:35 am

        That’s a combination of both! Downwards is a little more difficult than upwards – you probably need to do a query on the Account object and not the Contact object to get that data!

        Reply
jayakumar
February 11, 2014 @ 2:05 am

this is stuff is really really great.you have our gratitudes.

Reply
Chris
October 6, 2013 @ 5:04 am

Thank you so much! Really looking forward to FOR and FOREACH :) This set of guides is going to be devoured by Salesforce coding beginners – thanks again .

Reply
    David Liu
    October 6, 2013 @ 10:44 am

    Glad you like the site, Chris!

    Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *


*

*

Theme: Simple Style by Fimply