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!

Quiz Answers – Chapter 5

February 24, 2014

Preface: this post is part of the Bulkify Your Code series.
View Chapter 5 quiz questions without the answers!

Chapter 5 Questions:

1. True or false. There is always a way around any Governor Limit.

True! Never feel like beating a Governor Limit is too difficult – it’s definitely possible and someone has done it before!

2. True or false. Code will not be able to by deployed if it hits Governor Limits.

False. Salesforce only runs your test classes against the code that you’re going to deploy. So if your test class doesn’t follow Principle of a Good Test Class #4, you’ll receive a errors in production but not your sandbox environment!

3. True or false. Without any changes to code, it’s possible for a trigger to hit Governor Limits on one run, and pass Governor Limits on another.

True. The most common example is when a trigger works when a user insert/updates a single record and it works, however the trigger breaks when the user tries to insert/update multiple records at the same time. Another example is when your SOQL queries query too many unnecessary records – once your Salesforce database grows to a certain size your triggers will suddenly break!

4. An identical search term has been added to a Map for a second time – this time with a different search result. What happens when the Map is searched using this search term?
(a) An error occurs when adding the second result
(b) The first search result is returned
(c) The second search result is returned
(d) Both search results are returned in a search

(c) Using put on the same search term will always override the previous search result.

5. Different search terms are added to a Map – both with the same search result. What happens when the Map is searched?
(a) An error occurs when adding the second result
(b) When searching the first term, an error occurs
(c) When searching the second term, an error occurs
(d) The same search result is returned for both search terms

(d) It’s perfectly OK to have multiple different search terms return the same result.

6. True or false. It’s OK to have SOQL inside a loop if you know 100% you’ll only have one record in the loop.

Never have a SOQL query in a loop! There is always a better way to do it so don’t get tempted! Salesforce orgs are constantly changing and it’s impossible to say that you’ll never have more than one record in a loop.

7. When combining SOQL queries, why is it better to query against a Set of potential values instead of a List?

Although both will work, Sets are more flexible with duplicate values so you don’t need to worry about potentially running into errors. The primary reason to use a List is because it preserves the order of records, however when used in a SOQL query the order doesn’t matter at all!

Chapter 5 Practice Trigger
Write a trigger that populates an “Owner’s Manager” lookup field on opportunities based on the opp owner’s (user’s) standard ManagerId field. Don’t forget the test class!

trigger OMgr on Opportunity (before insert, before update) {
  // Get the set of all owners
  Set<Id> ownerIds = new Set<Id>();
  for (Opportunity opp : Trigger.new) {
    ownerIds.add(opp.OwnerId);
  }
  
  // Create a map of users to managers  
  List<User> users = [SELECT Id, ManagerId 
                       FROM User 
                       WHERE Id IN :ownerIds];
  Map<Id, Id> userToMgr = new Map<Id, Id>();
  for (User u : users) {
    userToMgr.put(u.Id, u.ManagerId);
  }
  
  // Set the opp field to the owner's manager
  for (Opportunity o : Trigger.new) {
    o.Owner_Manager__c = userToMgr.get(o.OwnerId);
  }
}

Test class:

@IsTest
public class TestOMgr {
  static testmethod void testOppMgrs() {
    // Create manager
    User mgr              = new User();
    mgr.Username          = 'govlimitking@gmail.com';
    mgr.Email             = 'govlimitking@gmail.com';
    mgr.FirstName         = 'No';
    mgr.LastName          = 'Worries';
    mgr.Alias             = 'ez';
    mgr.CommunityNickname = 'lifeisgood';
    mgr.ProfileId         = '00ei0000000rTfp';
    mgr.TimeZoneSidKey    = 'GMT';
    mgr.LocaleSidKey      = 'en_US';
    mgr.EmailEncodingKey  = 'ISO-8859-1';
    mgr.LanguageLocaleKey = 'en_US';
    insert mgr;

    // Create user w/above manager
    User owner              = new User();
    owner.Username          = 'govlimitqueen@gmail.com';
    owner.Email             = 'govlimitqueen@gmail.com';
    owner.FirstName         = 'No';
    owner.LastName          = 'Prenup';
    owner.Alias             = 'dollaz';
    owner.CommunityNickname = 'cashmunny';
    owner.ProfileId         = '00ei0000000rTfp';
    owner.TimeZoneSidKey    = 'GMT';
    owner.LocaleSidKey      = 'en_US';
    owner.EmailEncodingKey  = 'ISO-8859-1';
    owner.LanguageLocaleKey = 'en_US';
    owner.ManagerId         = mgr.Id;
    insert owner;
    
    // Create 200 opps to test gov limits
    System.runAs(owner) {
      List<Opportunity> opps = new List<Opportunity>();
      for (Integer i = 0; i < 200; i++) {
        Opportunity o = new Opportunity();
        o.Name        = 'Biggest Deal of All Time';  
        o.Amount      = 10;
        o.CloseDate   = Date.today();
        o.StageName   = 'Prospecting';
        opps.add(o);
      }
      insert opps;
    }
    
    // Make sure everything worked!
    List<Opportunity> newOpps = [SELECT Id, Owner_Manager__c
                                  FROM Opportunity];
    for (Opportunity o : newOpps) {
      System.assertEquals(mgr.Id, o.Owner_Manager__c);
    }
  }
}
34 Comments
Priya
May 23, 2019 @ 8:18 am

Please let me know where I went wrong, why cant i use map? Please provide more explanation of what the data types should be when using maps.

trigger OppManager on Opportunity (before insert, before update) {
Set allOppOwnerIds = new Set();
for(Opportunity newOpp : Trigger.new){
if(newOpp.owner != Null){
allOppOwnerIds.add(newOpp.ownerId); }
}
List userManagersList = [Select Id, ManagerId From User
Where Id = :allOppOwnerIds];
Map oppOwnerToUserId = new Map();
for(User u : userManagersList){
oppOwnerToUserId.put(u.ManagerId, u);
}
for(Opportunity newOpp : Trigger.new){
if(newOpp.owner != Null){
User oppOwner = oppOwnerToUserId.get(newOpp.ownerId);
if(oppOwner != Null){
newOpp.Owners_Manager__c = oppOwner.Id;
}
}
}
}

Reply
Aayushi
July 7, 2017 @ 12:28 am

Hi David,

I know this post is old not sure if you would reply. Just wanted to get my solution cross checked so that I know I was on the right track.
trigger PopulateManager on Opportunity (before insert,before Update) {

Map oppMap=new Map();
List oppList=[Select Id,Owner.ManagerId from Opportunity where Id IN :Trigger.New];
for(Opportunity opp: oppList){
oppMap.put(opp.Id, opp);
}
for(Opportunity opp: Trigger.New){
Id Manager=oppMap.get(opp.Id).Owner.ManagerId;
System.debug(‘Manager: ‘+ Manager);
opp.Owner_Manager__c=Manager;
}
}

Thanks

Reply
    Aayushi
    July 7, 2017 @ 3:42 am

    I have done a major blunder of using before insert in my case since I am querying Id of Opp.

    Reply
Parker Edelmann
February 27, 2017 @ 11:57 am

Hi David,

I’m wondering why my code here didn’t work as expected. It’s not recognizing that the Owner Object is not null… I didn’t think that the SOQL and Maps were necessary as all of the information should be in the Opportunity’s Owner’s information.

trigger popOwnerManager on Opportunity (before insert ) {

for (Opportunity opp : Trigger.new) {
System.debug(opp.Name + ‘ is in the trigger’); //Returns the name properly
System.debug(opp.OwnerId); //Returns my id
System.debug(opp.Owner.ManagerId); //Returns null
System.debug(opp.Owner); //Also returns null
if (opp.Owner.ManagerId != null) {
System.debug(opp.Owner.ManagerId + ‘ will be the new Owner\’s Manager.’);
opp.OwnersManager__c = opp.Owner.ManagerId;
} else{
System.debug(‘opp.Owner.Manager.Id = null’);
}
}
}

Why isn’t it recognizing the Owner Object? If it did, then no SOQL would be necessary.

Thank you so much for putting this website together!

Best Regards,
Parker Edelmann

Reply
    David Liu
    February 27, 2017 @ 7:48 pm

    Gotta use SOQL to get information from other objects!

    Basically, if you have more than one period, you need SOQL.

    Examples with one period:
    opp.Name
    opp.OwnerId

    Examples with more than one period:
    opp.Owner.ManagerId
    opp.Owner.Manager.CreatedById

    Cheers!
    David

    Reply
radha
March 31, 2015 @ 9:45 pm

when i am running this test class i am getting this error “INVALID_CROSS_REFERENCE_KEY, invalid cross reference id: []” can u please explain thanks in advance

Reply
    Stijn Blommerde
    December 23, 2015 @ 7:57 am

    same problem here. when i copy paste the solution i also get an error:

    System.DmlException: Insert failed. First exception on row 0; first error: INVALID_CROSS_REFERENCE_KEY, invalid cross reference id: []

    Class.Test_OwnerManager.testOppMgrs: line 17, column 1

    Reply
radha
March 9, 2015 @ 1:06 pm

“ownerIds.add(opp.OwnerId)”
“userToMgr.put(u.Id, u.ManagerId);”
the field names i have seen them as owner and manager in opportunity and user objects
do we need to append id to those fields?
thanks in advance

Reply
    Mayank Srivastava
    March 9, 2015 @ 1:09 pm

    Radha,
    Owner and Manager are lookup fields that’s why it’s a must to append Id to those field names.

    Reply
      radha
      March 17, 2015 @ 11:14 pm

      thank u for answering my basic questions

      Reply
radha
February 23, 2015 @ 12:52 pm

Instead of using map I used lists, this trigger is not working, the potential duplicate fields are not getting updated
can u please check out this
thank u

trigger leadandcontactdupes on Lead (before insert ,before update)
{
set names = new set();
for(lead trlead : trigger.new)
names.add(trlead.name);

List leads = new List([select id , name from lead where name in : names]);
List contacts = new List([select id,name from contact where name in : names]);
//for each record being inserted
for(lead trlead : trigger.new)
{
//compare with names of all leads
for(lead ld:leads)
{
if (trlead.name == ld.name)
trlead.Lead_potential_duplicate__c=ld.id;
}
// compare with all names in contacts
for(contact ct:contacts)
{
if(trlead.name == ct.name)
trlead.contact_potential_duplicate__c=ct.id;
}
}
}

Reply
    David Liu
    February 23, 2015 @ 7:37 pm

    Save yourself the trouble and use a Map instead! Start good habits early!

    Reply
radha
February 23, 2015 @ 11:48 am

List contacts = new List([select id,name from contact where name in : trigger.new]);
i am getting error” invalid bind expression—-”
please explain thank u

Reply
    David Liu
    February 23, 2015 @ 7:45 pm

    Trigger.new is a list of records, and you’re trying to compare a “Name” field with an entire record!

    You need to create a separate list of names from Trigger.new and use that instead.

    Reply
      radha
      February 27, 2015 @ 1:35 pm

      thank u

      Reply
Supriya
February 19, 2015 @ 1:41 pm

You can further optimize the SOQL and Map code to:

Map userToMgr = new Map();
for (User u : [SELECT Id, ManagerId
FROM User
WHERE Id IN :ownerIds]) {
userToMgr.put(u.Id, u.ManagerId);
}

A little help towards avoiding heap size limit ;)

Reply
Mayank Srivastava
February 16, 2015 @ 3:15 pm

Hey David,
I know we are are trying to implement the “Owner’s manager” logic using a lookup field (which needs code) and this again might be for practice but if we really wanted to implement this, wouldn’t a custom formula field (text type) have been more appropriate and recommended in this scenario?

Reply
    David Liu
    February 16, 2015 @ 5:22 pm

    This one’s definitely for practice!

    That said, the scenario could be that you need many fields from the owner’s manager in a report, and it wouldn’t make sense to make a ton of formula fields as a workaround.

    Reply
Faraz Mohammad Khan
January 19, 2015 @ 10:48 pm

Hey David,

here’s my stab at it

trigger AssignManager on Opportunity (before insert) {

Set allOwners= new Set();
for (Opportunity opp: Trigger.new){
allOwners.add(opp.OwnerID);
}

if(allOwners!= null && allOwners.size()>0){
Map managerToUserMap = new Map();
for(User u : [Select Id,ManagerId from User where Id in :allOwners]){
managerToUserMap.put(u.ID,u.ManagerId);
}

for (Opportunity opp: Trigger.new){
opp.OwnerManager__c=managerToUserMap.get(opp.OwnerID);
}
}
}

Reply
Geoff
October 21, 2014 @ 10:57 am

Hi David,
I’m just comparing your test class to mine on the practice trigger above.
I had also included a section where I updated the opportunity to be owner by the manager figuring I should also test:
1) the before update side
2) a user without a manager as the owner
Are both of those things something that should be included or are they unnecessary in this case? If so, why? If I comment out that section I still get 100% coverage but I’m not testing the before update and I would have thought the test coverage would have picked that up.

Thanks again!

Reply
    David Liu
    October 21, 2014 @ 12:28 pm

    Those are both great test cases!!

    If this were the DEV 501 test you woulda just got some extra points!

    Reply
Jasmine
October 7, 2014 @ 11:49 am

Hi David!

Quick question. I noticed that on number 6 you said that it’s never okay to have a SOQL query in a loop. However, isn’t that what you did for the solution to Chapter 4’s Practice Trigger?

Reply
    David Liu
    October 8, 2014 @ 7:24 am

    Great observation =) At the time of Chapter 4, I had not taught bulkification yet so I did not require that in the quiz =)

    Reply
Alison
September 2, 2014 @ 12:41 pm

Hi David,

For the first part of the trigger, why would the following not work?:

for (Opportunity opp :Trigger.new){

List owner = [SELECT Id, ManagerId from User where Id =:opp.OwnerId];

Thank you so much, and thanks for such an amazing site!!

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

    Technically it would work but you’d run into governor limits on any bulk data jobs, breaking your code!

    (check out the first post in chapter 5 for more info!)

    Reply
    Shail
    September 15, 2014 @ 7:42 pm

    Bad idea to have SOQL inside for loop Alison

    Reply
Visal
August 24, 2014 @ 3:27 pm

Hello David,

I am bit late to do this quizz :-)). I got this error in Saleforce. What I understand is it’s trying to tell me that I am trying to math an object with Id but Owner_Manager__c is a custom field that I have created in Opportunity.

Would you please help me to settle this problem ? Thank you in advance

I have copied the full code as following:

Error Error: Compile Error: Illegal assignment from Object to Id at line 21 column 2
****** This is the last line of code u.Owner_Manager__c = u.get(u.OwnerId); *********

trigger ManagerName on Opportunity (before insert, before update){

// Step1: Create a set of Id to query
Set ownerId = new Set();
for(Opportunity newOpp : trigger.new){
OwnerId.add(newOpp.OwnerId);
}

// Step 2: Query for Manager Id of Owner
List mId = [SELECT Id, ManagerId from USER WHERE Id = :ownerId];

// Step 3: Create a map of Owner with Manager.
Map OwnerToManager = new Map();
for(User T : mId){
T.put(T.id,T.ManagerId);
}

// Step 4: Search for Manager
for (Opportunity u : trigger.new){
u.Owner_Manager__c = u.get(u.OwnerId);
}
}

Reply
    Shail
    September 15, 2014 @ 7:47 pm

    // Step 4: Search for Manager
    for (Opportunity u : trigger.new){
    u.Owner_Manager__c = OwnerToManager.get(u.OwnerId);
    }

    Reply
ammu
March 3, 2014 @ 6:56 pm

Hi David

I stumbled upon your site when looking for good resources to learn Apex and I must say you’ve done an awesome job at maintaining such a wonderful site.I am new to Apex and after reading the first five chapters, I feel really confident.Thank you for putting in so much effort to help others learn Apex.I tried to write the practice trigger and realized my version differs from the answer you have given.Could you please let me know if the following version is also ‘acceptable’ if not the ‘best’.

Trigger getOppOwnerManager on Opportunity(before insert)

{

// STEP 1 – Get the set of opportunity owners

SET oppowners= new SET();
for(opportunity opp : trigger.new)
{
if(opp.owner != NULL)
{
oppowners.add(opp.owner);
}
}

// STEP 2 – Get the list of users whose name is present as an opportunity owner name

List managers = new list();
managers = [select id,manager__c from user where name in : oppowners];

// I have a custom field called manager on the user object that has a hierarachical relationship.

// STEP 3 – Create a map where the keys are opportunity owner names and the values are users objects(with manager field)

Map ownersmanager = new MAP();
for(user u : managers)
{
ownersmanager.put(u.name,u);
}

for(opportunity opp : trigger.new)
{
if(opp.owner != null)
{
user oppmanager = ownermanager.get(opp.owner)
opp.ownersmanager__c = oppmanager.manager__c;
}
}

}

Thanks in advance.

Reply
    David Liu
    March 3, 2014 @ 10:50 pm

    You should be very proud of your code =)

    I would tell you that if it works, then what you have here is good code. That’s not always the case, but I can tell this based off the general structure of your code. I can’t tell if it works because the commenting system on my site takes out some fundamental characters.

    The fundamental difference between what you have written here and what I wrote in the answer is that you use the Owner Name as a key where I use the Owner ID as a key. Both work. The ID is slightly better in a highly, highly, highly unlikely scenario where there are multiple different owners with the exact same name. Even then, your code will still work and not break. So, short answer you should be very proud of your code.

    In the future consider using IDs as they are guaranteed 100% unique. If you ever work in a large org (millions of records) with a duplicate problem then IDs will be your only real option as you’ll hit governor limits otherwise.

    Keep on coding, you’re making great progress. I look at my user statistics and by far the majority don’t make it to Chapter 5, so you have an unusually strong will. This will get you far as a coder. If you ever make it one day as a Salesforce developer come find me I would like to talk to you.

    David

    Reply
      ammu
      March 5, 2014 @ 6:31 am

      David,

      Thank you :-).Thank you very much for the inspiring words..Coming from you, they mean a lot.

      I will keep your suggestions in mind when writing new code snippets.Eagerly waiting for your explanation on batch and scheduler apex as well as integration concepts.Also, I would like to start learning Visualforce since every SFDC developer is expected to know Visualforce in addition to Apex.Could you suggest the best way to go about it?

      Thanks

      Reply
        David Liu
        March 5, 2014 @ 8:56 pm

        Interesting fact: no Salesforce developer interview I’ve ever had touched Visualforce (even though I spend a lot of time doing it!).
        I also usually don’t test people on Visualforce. This is for a few reasons:
        – the Apex side of things is more difficult. The thought process generally requires deeper thinking
        – Apex is much less forgiving. There may be 20 ways to do something in Visualforce but only a few ways in Apex

        You should still study Visualforce though I highly recommend it. Learning from scratch from the official guide is not as difficult as learning Apex from the guide:
        http://www.salesforce.com/us/developer/docs/pages/index_Left.htm

        Other than that, stay tuned because I’m already thinking about how to best teach Visualforce to you guys (after advanced Apex)!

        Reply
Laci
February 24, 2014 @ 11:53 pm

Shouldn’t the answer to Q4 actually be (c)? If second search result replaces the first one because it uses the same search term as the key, when the set is queried the second (last one added) search result would be returned.

Reply
    David Liu
    February 25, 2014 @ 12:22 am

    Great call Laci!!!!!!!!!!!! Thank you and updated!!!

    I am also glad that people are actually reading these hahahaha.

    David

    Reply

Leave a Reply Cancel reply

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


*

*

Theme: Simple Style by Fimply