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!
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?
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
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.
my test class:-
@isTest
public class Loops {
static testMethod void testtrig () {
Contact c = New Contact();
c.FirstName = ‘Dream’;
c.LastName = ‘world’;
}
DML Statement is missing in your code.
Add this statement at last:
insert c;
and you coverage will rise to 100% :)
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;
Try asking the official developer forums!
DML Statement is missing in your code.
Add this statement at last:
insert c;
and you coverage will rise to 100% :)
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.
It might not be on the User object!
https://www.salesforce.com/developer/docs/api/Content/sforce_api_objects_user.htm
I found it. It is on User object with API name of UserPreferencesHideS1BrowserUI.
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;
}
}
Looks like you switched this line:
c1 = a1.Primary_Liaisons__c;
It should be:
a1.Primary_Liaisons__c = c1;
Give it a shot!
David
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
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
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;
}
}
}
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;
}
}
}
a1.Contacts isn’t in scope of the trigger since it’s technically another object. Need to use SOQL like you did!
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!
You’d have to query for it first (outside a loop), then traverse downward. The traversal itself wouldn’t be a query!
Ahh now it’s all making sense. Thanks!
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 :)
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.');
}
}
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;
Assume myContact is the result of a prior SOQL query on the Contact object!
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
Thanks!
You can just assume that myContact was the result of a SOQL query (check out Chapter 2 to learn more)!
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?
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 (-;
Thank you Viru, great advice!!! (=
My Pleasure David ! (-;
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 !
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!
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!
Holy cow this is a wonderful story!!!!
Want to write a post about it on this site? =)
David
dvdkliu+sfdc99@gmail.com
Sorry David — didn’t mean to talk about myself — your opening sentence on this page took me back to my time! :)
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!
Oh, ok, sure, just let me know the next steps.
Email sent!
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!
Awesome work dude. very helpful……………
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.
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
Awesome It worked.. Thank you so much David. You Rock!
^_^
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!
Thank you Ian, tell your friends!
Links are now updated!
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.
Once you write your first few triggers you’ll wonder why you were ever scared in the first place! You can do it!
David
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
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
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?
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!
this is stuff is really really great.you have our gratitudes.
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 .
Glad you like the site, Chris!