Preface – This post is part of the Core Apex Tools series.
Data collections are simply groupings of any data type.
You’ll use data collections often because they go hand in hand with SOQL.
Lists are the first and most important of the three data types:
List<Contact> peopleToSpam = [SELECT Id, Email FROM Contact];
The reason why Lists are so important is because the output of every SOQL query is a List. The unique aspect of Lists is that they are ordered – had we ordered our SOQL query by Email address, this structure would be preserved in our variable!
Since Lists are ordered, you can get specific elements of your List by the element’s index, or, List position. Indexes start at zero and go all the way up to number of records in your list, minus one! So if you wanted to get specific elements of your List, you could do this using brackets:
Contact firstContact = peopleToSpam[0]; Contact lastContact = peopleToSpam[peopleToSpam.size() - 1];
Notice how we used dot notation to get the size of the List, then subtracted one from this value to get the last element! If our list had 100 elements, we could have gotten the exact same results using peopleToSpam[99].
You can do some incredible stuff when combining lists and SOQL:
List<String> doNotSpam = new List<String>(); doNotSpam.add('dvdkliu+sfdc99@gmail.com');
// Don't want to spam myself! List<Contact> peopleToSpam =[SELECT Email FROM Contact WHERE NOT (Email IN :doNotSpam)];
Take a moment to read over the code and fully understand what it’s doing. I like to pretend I’m a robot when reading code. It really helps to understand how Salesforce interprets your code!
Sets aren’t used as often in Apex – they’re basically lists however they’re unordered and don’t allow any duplicate values. Don’t worry about Sets for now!
Maps are the final type of collection and they’re actually extremely powerful. A map essentially lets you “search” through a list for a particular value! I’ll cover these at a later point – Maps deserve their own post but you won’t need to use them for a while.
Next post: Dot notation – navigating relationships and using methods!
Hi
I am trying this trigger for updating the Delivery Date in Service Request Child object from Asset Parent Object, But I am getting this error : Variable does not exist: asse
trigger Trg21 on Service_Request__c (After insert) {
Set assetnum=new set();
For (Service_Request__c s: trigger.new){
assetnum.add(s.Asset__c);
}
List assetlst=[Select id,Delivery_Date__c from asset where id in :assetnum];
Map stor=new Map();
For (Asset asse: assetlst){
stor.put(asse.id,asse);
}
For (Service_Request__c s: trigger.new){
s.Asset_Delivery_Date__c=stor.get(asse.Id);
}
}
I think you need to declare the datatype of set.
Hi David
Thanks a lot for your extraordinary help!
I need to ask you something… how do you pretend you are a robot when reading code??? ;)
As stated in… Take a moment to read over the code and fully understand what it’s doing. I like to pretend I’m a robot when reading code. It really helps to understand how Salesforce interprets your code!
Basically meaning that assume you have no preconceived notions of the world and can only do exactly as you are told!
hi david,
i have a question like
how to pass list to trigger handler
i want to call list of accounts and its related contacts using map but contatcs should be in picklist form
O_o not even sure what you’re asking!
nice
Hi David,
I am a very new to Sfdc.I need to learn Sfdc.what I have to do.Can u please help me.
Thanks,
Prasanna
Right here!
https://www.sfdc99.com/beginner-tutorials/
dhopama upor uttovo
Hi David
am getting below error while saving trigger
Error Error: Compile Error: line breaks not allowed in string literals at line 4 column -1
trigger code
trigger createOpp on Account (before insert)
{ for (Account acc : trigger.New) {
Opportunity o = new Opportunity();
o.Name = ‘Opportunity Name’;
o.CloseDate = System.today();
o.StageName = ‘Qualification’;
insert o;
}
}
pls advise
More debugging!
https://www.sfdc99.com/2014/02/22/debug-your-code-with-system-debug/
Please try this.
trigger createOpp on Account (after insert)
{
for (Account acc : trigger.New) {
Opportunity o = new Opportunity();
o.Name = ‘test’;
o.AccountId= acc.Id;
o.CloseDate = System.today();
o.StageName = ‘Qualification’ ;
insert o;
}
}
use DML Operations out side the loops.
trigger createOpp on Account (before insert)
{ for (Account acc : trigger.New) {
Opportunity o = new Opportunity();
o.Name = ‘Opportunity Name’;
o.CloseDate = System.today();
o.StageName = ‘Qualification’;
}
insert o;
}
Hey David,
This is Surya here. Your website is very useful sfdc developers and especially for rookies like me.
I have started my career in Salesforce as Salesforce developer trainee. I am new to the concepts and learning it everyday.
I need your guidance in Collections especially in Sets and Maps in order to cope up with my team to move forward everyday.
Hope you will help the guys like me in the concepts in the near future. :)
Check these posts out!
https://www.sfdc99.com/2013/09/28/data-collections-lists-sets-and-maps/
https://www.sfdc99.com/2014/01/12/introduction-maps/
David
hi David.
my requirement is to display all objects in a VF page and it should also specify whether they are standard or custom.
Try the official developer forums!
can we use a List inside a Map
You sure can!!!
“Map keys and values can be of any data type—primitive types, collections, sObjects, user-defined types, and built-in Apex types.”
https://www.salesforce.com/us/developer/docs/apexcode/Content/apex_methods_system_map.htm
Hi David,
Having a doubt regarding List . As u stated with List, the elements are sorted, and given the example as below.
List peopleToSpam = [SELECT Id, Email FROM Contact];
Contact firstContact = peopleToSpam[0];
Contact lastContact = peopleToSpam[peopleToSpam.size() – 1];
In which aspect you have concluded that firstContact is peopleToSpam[0] . Thanks in Advance.
Great question!
Imagine I had sorted the list by email address =P
As it is in the example the firstContact would’ve essentially been random (actually I believe Salesforce sorts by created date default)
Hi David,
I have a doubt. we always using List to insert. so, my doubt is shall we insert data using set and Map.
If you have a Set or Map you simply convert it to a list =)
Hi David,
I have a requirement to fulfill on Monday . I am new to Salesforce coding (triggers and Apex) and as I am the only one to do I don’t know how to achieve this in such a short notice .Please help me out with this.Would really appreciate it.
1> There is a relationship between “Account” and a custom object “territory filed” aka (TSF) . and there is also a relationship between account and another custom object “Affiliation” which also stores the accounts based on some other rules and regulations depending on user’s choice.
2> In TSF object I have created a lookup field (“primary affiliation”) of account . Now my requirememt is that when a user creates or edits the TSF object record and goto that lookup field to select the account and if the user select the account which is also the one in the affiliation object then its fine , trigger won’t hit and allow user to select the account and save the TSF record but if it is otherwise then- it should throw the error saying that the selected account is not your affiliation account.
So far what I have understood –
I need to create a lookup field .
in the trigger i need to first fetch all the list of affiliations associated in that account.
Then i need to fetch the account_id which user is selecting in that lookup – then I need to compare the ID of that selected account against the list of account_ids in the affiliation and if it is false then I need to trow the error.
Please help me to achive this , Idon’t know how to fetch the records using list or map or set . even if I read your tutorial I can’t able to apply that in my code.Please guide me to achieve this . I know this is somenthing of not very hard to achieve but help but be greatly appriciated.
Thanks in advance David.
If you study hard you can do it!!! Believe in yourself =)
Hi, is there any difference b/w list1= list2; and list1 = list2.clone();
The classic “Pass by reference” or “Pass by value” question!
Check this post out:
https://developer.salesforce.com/blogs/developer-relations/2012/05/passing-parameters-by-reference-and-by-value-in-apex.html
It’s been a long back you have raised this. But, I have a small doubt. I have gone through link shared by David. And I think I understood the difference between the raised query.
List 1 = List 2 : Allocates different memory for both lists and technically are diff.
List 1 = List 2.Clone(); Allocates exact details of list 2 to list 1.
Is my understanding right :(
Please help me
Thanks
Prassu
Thanks David…you are genius.
Hi David,
You stated that “output of every SOQL query is a List” but I believe you can also load a Map from SOQL. Am I correct ?
Great observation!
The output of every SOQL query is definitely a list!
However note that when creating a Map, one of the arguments you can use in the constructor is a list! So by using a SOQL query inside a Map constructor, you’re using a list in the Map constructor.
Here’s the documentation on this!
http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_methods_system_map.htm#apex_System_Map_ctor
David
Hi David,
I didn’t understand concept of List. In the below of your code i am not sure what is the use of List.
// Automatically create an Opp when an Account is created
trigger AutoOpp on Account(after insert) {
List newOpps = new List();
for (Account acc : Trigger.new) {
Opportunity opp = new Opportunity();
opp.Name = acc.Name + ‘ Opportunity’;
opp.StageName = ‘Prospecting’;
opp.CloseDate = Date.today() + 90;
opp.AccountId = acc.Id; // Use the trigger record’s ID
newOpps.add(opp);
}
insert newOpps;
}
I have written code like below and it worked.
trigger createOpp on Account (before insert)
{ for (Account acc : trigger.New) {
Opportunity o = new Opportunity();
o.Name = ‘Opportunity Name’;
o.CloseDate = System.today();
o.StageName = ‘Qualification’;
insert o;
}
}
Can you please let me the difference.
H David,
I didn’t understand List Concept. In the below example of your trigger
// Automatically create an Opp when an Account is created
trigger AutoOpp on Account(after insert) {
List newOpps = new List();
for (Account acc : Trigger.new) {
Opportunity opp = new Opportunity();
opp.Name = acc.Name + ‘ Opportunity’;
opp.StageName = ‘Prospecting’;
opp.CloseDate = Date.today() + 90;
opp.AccountId = acc.Id; // Use the trigger record’s ID
newOpps.add(opp);
}
insert newOpps;
}
What is the use of list in the above code.
There are two ways to do this code with the same results:
1. Good way: Create a list, add all records to the list, then use the insert DML on the list
2. Bad way: Don’t create a list, insert DML each record one by one
The first is preferred because it scales better, while the second one may have errors if you’re trying to insert many records!
Thank You David. Please ignore my other post.
David,
I know, I am really screwed up here …
trigger TEST on ObjectA__c (after insert, after update)
{
List EntryIds = New List();
for(Availability_Template_Entry__c o : Trigger.new){
if(o.FieldA__c != NULL ){
EntryIds.add(o.FieldA__c);
}
List EntryList = [SELECT id, FieldB__c FROM ObjectB__c WHERE id in :EntryIds];
for(integer i = 0 ; i < EntryIds.size(); i++)
{
EntryIds[i].ObjectB__c.Field2__c = ObjectA__c.TOTAL__c;
}
}
}
I am making this very simple code but I cannot get it to work. This is supposed to update
FieldB of ObjectB with the value found on FieldA of ObjectA.
I am dead meat but can you help?
Thanks in Advance David …
More Power to SFDC99 !
A couple changes I recommend:
1. First off the trigger object and the Trigger.new object don’t look the same but it might be because you’re changing the object names around!
2. Instead of looping across EntryIds I recommend looping across EntryList =)
Best of luck!
David
Hi David
Can maps have duplicate keys? If yes, how to retrieve specific values?
Definitely does not allow duplicate keys! There is a question regarding this on this chapter’s quiz:
https://www.sfdc99.com/2014/02/18/quiz-chapter-5/
If you’re ever finding yourself in a case where your keys aren’t unique, try combining the key with another field to get a truly unique key!
IE create a new “combined” key of ID1 + ID2
Thanks for being so prompt David. I really appreciate it.
Hi David,
You wrote a query like [SELECT Email FROM Contact WHERE NOT (Email IN :doNotSpam)]
.My question is,You are searching an email in list right..for one value its k…if the list contains more than 1 then how it works? i need to know…..because from collections we cant get values directly right,can get using iterators or enumerat
ions..so that’s y i got this question.correct if i’m wrong.
Thanks,
Srinivas.
Hi David,
I have created two custom fields that are identical, one in Product Line Items on my opportunity, and one in my Quote Line Items on my Quotes. The fields are called ‘Start Date’ which is the start date of a contract, there are also two other custom fields, both on the opportunity and quote objects, they are called ‘Duration’ (this is the number of months one of our contracts is for’ and the ‘End date’ which is quite self explanatory. I enter the start date as normal, and am able to enter a number (of months) into the duration field which will calculate the end date, e.g.
Start Date 01/01/2014 Duration: 12 = End date 01/01/2015
The problem I am having is getting this information to be brought across from the Product Line Items, into my Quote line items just like it brings over the product names, etc.
Having just started to learn apex coding I have had a few attempts but not really ever finished it. There is a lot of reading and learning to go through. I did a little of Java at college but that was about 3 years ago so I’m struggling to not get stuck and bang my head against the keyboard. The bigger problem is that I need to complete this by next week, as the I have changed the Quote process to be able to attach multiple Quotes to one email at one time, but this has taken a lot longer than expected.
Do you have any way of helping me at all?
Best regards,
Emma :)
Hey Emma,
No problem!
So the problem is:
1. Opps are created with Opp Line Items
2. A Quote is then created on the Opp and Quote Line Items are added via the Sync button
3. Custom info from Opp Line Items need to be automatically transferred to the Quote Line Items (based on a product match)
– Start Date
– Duration
And you are looking for code in step #3 to keep the opp and quote line item custom fields in sync!
Let me know if this is right and we can get to coding!
David
Hi David,
Sorry I have been on annual leave from work so just got your message.
You’ve kind of got it but not quite,
1. Opps are created with Opp Line Items – Yes
2. A Quote is then created on the Opp and Quote Line Items are added via the Sync button – Not quite, when I create a Quote (by clicking the new quote button on the Quote object within the Opportunity object, so yes on the Opp just making it clearer for myself), all of the product info (apart from my custom info) is taken over into the quote automatically, every single time I create a new quote. The only time I would use the ‘start sync’ button, would be if I had created a number of quotes which are all different and my customer comes back and chooses Quote 3a, I need this to reflect on the opportunity as changes have been made. Another problem with this is that if I do ‘Start Sync’, the custom information is not synced to the Opportunity.
3. Custom info from Opp Line Items need to be automatically transferred to the Quote Line Items (based on a product match)
– Start Date
– Duration
– End date
I hope I haven’t confused things.
Let me know.
Thanks!
Emma
Since you’re an Sfdc99 original I’m going to code this for you Emma! Check your email!
David
can u please post the link for leads, opportunities,quotes to understand the cycle
thank u in advance
Thank you so much for this amazing and helpful website. Please don’t forget about Maps, I’ve understood the basic concepts of Lists and Sets very well from you, and I’m looking forward to understanding Maps. Although you mentioned that we won’t need to use Maps for a while, at work here we use almost every day. I just started my career in Salesforce developing and I’m trying to learn and catch up with my coworkers.
Hey Seemo,
Maps will come soon but not in Chapter 3 or 4!
In the meantime, just imagine Maps to be like a search. Say you want to be able to search for someone’s name by looking up their email address. You can build a Map to solve for this. The first String is the exact email address, and the second is the person’s name.
yourMap.put(‘david@gmail.com’, ‘David Liu’);
yourMap.put(‘seemo@gmail.com’, ‘Seemo’);
Then you can “search” your map like this:
yourMap.get(‘seemo@gmail.com’);
The above will return ‘Seemo’.
You don’t have to use strings, you can use IDs, numbers, even sObjects!
David
Hey David.
I am very much interested in your salesforce topics. I am a rookie to salesforce and have started my career in it. Need your help in Salesforce topics especially in Collections such as Maps, lists and Set. Although I am good at Lists , I am not pretty good at Set and Maps. Need your guidance in Maps especially.
Hope you will help me in the near future! :)
Everything you need to know right here!
https://www.sfdc99.com/2014/01/12/introduction-maps/