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!

Apex Video Tutorial: Combine SOQL & Apex

July 2, 2014

Preface: This video is part 3 of the Official #Apex4Admins series presented by Salesforce and I!

Combine your knowledge from part 1 and 2 to write an epic deduping trigger!

  1. Lists and dot notation!
  2. Combining SOQL and Apex using bind varibles!
  3. How to write good test classes!
  4. Write a deduping trigger!

View slides

Lists

List<Food__c> dollarMenu = [SELECT Id, Name FROM Food__c WHERE Price__c = 1];
Food__c firstItem = dollarMenu[0]; // McChicken Food__c secondItem = dollarMenu[1]; // Sausage Biscuit Food__c thirdItem = dollarMenu[2]; // McDouble Food__c fourthItem = dollarMenu[3]; // Hash Browns
List<String> buddies = new List<String>();
buddies.add('Ronald McDonald'); buddies.add('Hamburglar'); buddies.add('Mayor McCheese'); buddies.add('Officer Big Mac');

Dot Notation

// Use Case #1: Access fields
String sandwichName = dollarMenu[0].Name;

// Use Case #2: Traverse relationships
String me = dollarMenu[0].Eaten_By__r.Name;

// Use Case #3: Access methods!
dollarMenu.remove(2); // Farewell McDouble
// Every data type has methods! Food__c newItem = new Food__c();
newItem.Name = 'bbq Ranch Burger'.capitalize();
dollarMenu.add(newItem);

Bind Variables

// Use variables inside your SOQL queries!
String bestMcDonaldsItem = 'Chocolate Dipped Ice Cream Cone';
List<Food__c> bestItems = [SELECT Id, Name FROM Food__c
WHERE Name = :bestMcDonaldsItem];
// You can use Lists as Bind Variables too List<String> dietFoodNames = new List>(); dietFoodNames.add('Apple Slices'); dietFoodNames.add('Side Salad'); dietFoodNames.add('Fruit & Yogurt Parfait'); List<Food__c> bannedFoods = [SELECT Id, Calories__c FROM Food__c
WHERE Name IN :dietFoodNames];

Test Class Principle #1: Create Records from Scratch

Contact dupeContact = new Contact();
dupeContact.LastName = 'Spiderman';
dupeContact.Email = 'spiderman@gmail.com';
insert dupeContact;
Lead dupeLead = new Lead();
dupeLead.FirstName = 'Peter'; dupeLead.LastName = 'Parker'; dupeLead.Company = 'Daily Bugle';
dupeLead.Email = 'spiderman@gmail.com';
insert dupeLead;

Test Class Principle #2: Use System.assertEquals()

// Example: This obviously comes out to true
System.assertEquals(true, bestWebinarEver);
// Example: This will give you an error and fail your test class!
System.assertEquals('Tom Brady', bestActiveQuarterback);
// Query the post-trigger values and assert assumptions dupeLead = [SELECT Id, Dupe_Contact__c FROM Lead WHERE Email = :dupeLead.Email LIMIT 1];
System.assertEquals(dupeContact.Id, dupeLead.Dupe_Contact__c);

Test Class Principle #3: Test Negative Scenarios Too!

// Create a lead that SHOULDN'T have a dupe
Lead uniqueLead = new Lead();
uniqueLead.LastName = 'Xavier';
uniqueLead.Company  = 'X-Men';
uniqueLead.Email = 'theprofessor@xmen.com';
insert uniqueLead; // Assert that a dupe isn't identified on the lead uniqueLead = [SELECT Id, Dupe_Contact__c FROM Lead WHERE Email = :uniqueLead.Email LIMIT 1];
System.assertEquals(null, uniqueLead.Dupe_Contact__c);

Test Class Principle #4: Test in Bulk!

// Add 200 new Contacts to a list
List<Contact> dupeContacts = new List<Contact>();
for (Integer i = 0; i < 200; i++) { Contact c = new Contact(); c.FirstName = 'David'; c.LastName = String.valueOf(i); c.Email = 'contact' + c.LastName + '@gmail.com';
dupeContacts.add(c);
} // Insert all 200 contacts at the same time
insert dupeContacts;

Deduping Trigger

// Populate a Contact Lookup field if there's a dupe!
trigger DetectDupes on Lead (before insert, before update) {
    for (Lead l : Trigger.new) {
        if (l.Email != null) {
            String leadEmail = l.Email;
List<Contact> dupeContacts = [SELECT Id FROM Contact
WHERE Email = :l.Email];
if (dupeContacts.size() > 0) {
l.Dupe_Contact__c = dupeContacts[0].Id;
} else { l.Dupe_Contact__c = null; } } else { l.Dupe_Contact__c = null; } } }

Deduping Trigger Test Class

@isTest
public class TestDeduper {
  static testMethod void testDupes() {
    // Principle #1: Create records from scratch!
Contact dupeContact = new Contact();
dupeContact.LastName = 'Spiderman'; dupeContact.Email = 'spiderman@gmail.com'; insert dupeContact;
Lead dupeLead = new Lead();
dupeLead.FirstName = 'Peter'; dupeLead.LastName = 'Parker'; dupeLead.Company = 'Daily Bugle'; dupeLead.Email = 'spiderman@gmail.com'; insert dupeLead; // Principle #2: Use System.assertEquals() dupeLead = [SELECT Id, Dupe_Contact__c FROM Lead WHERE Email = :dupeLead.Email LIMIT 1];
System.assertEquals(dupeContact.Id, dupeLead.Dupe_Contact__c);
// Principle #3: Test things that shouldn't work! Lead uniqueLead = new Lead(); uniqueLead.LastName = 'Xavier'; uniqueLead.Company = 'X-Men';
uniqueLead.Email = 'theprofessor@xmen.com';
insert uniqueLead; uniqueLead = [SELECT Id, Dupe_Contact__c FROM Lead WHERE Email = :uniqueLead.Email LIMIT 1];
System.assertEquals(null, uniqueLead.Dupe_Contact__c);
} }
5 Comments
Khushboo Vaidya
August 15, 2018 @ 3:59 am

Hi David,

Thanks for the amazing tutorials and precise content regarding Apex. I am in love with SFDC99 <3.
I just tried following the 4 principles of writing a good test class for this example by creating bulk data as below. When I try to run this class, it gives me 101 SOQL error: System.LimitException: Too many SOQL queries: 101 (at line 15).
I understand, I am trying to create 200 contacts in bulk here but I am inserting the data outside For each loop.
Can you please help me out here?

@isTest
public class myDetectDupesTest
{
static testMethod void createDupes()
{
List listOfBulkContacts= new List();

for(Integer i=0; i<=200; i++)
{
Contact c = new Contact();
c.LastName = 'testDupe' + i;
c.Email = c.LastName + '@gmail.com';
listOfBulkContacts.add(c);
}
insert listOfBulkContacts;

List listOfBulkLeads = new List();
for(Integer k=0; k<=200; k++)
{
Lead l = new Lead();
l.LastName = 'testDupe' + k;
l.Company = 'testDupeCompany' + k;
l.Email = l.LastName + '@gmail.com';
listOfBulkLeads.add(l);
}
insert listOfBulkLeads;

listOfBulkLeads = [SELECT Id, Dupe_Contact__c FROM Lead LIMIT 1];
System.assertequals(listOfBulkContacts[0].Id,listOfBulkLeads[0].Dupe_Contact__c);
}

Reply
    David Liu
    August 15, 2018 @ 11:39 pm

    Your triggers are inefficient =) Not the test class!

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

      Hi David,

      The trigger has pretty simple code as described below. Can you please help me find out what’s causing 101 SOQL issue?

      trigger myDetectDupes on Lead (before insert,before update) {
      for(Lead l: trigger.new)
      {
      //Ensure Lead has an email
      if(l.Email != null)
      {
      //Take that email into string(Apex variable) to use it in SOQL
      String leadEmail = l.Email;

      List listDupeContacts = [SELECT Id FROM Contact WHERE Email =: leadEmail];

      if(listDupeContacts.size() > 0)
      {
      l.Dupe_Contact__c = listDupeContacts[0].Id;
      }
      else
      {
      l.Dupe_Contact__c = null;
      }
      }
      else
      {
      l.Dupe_Contact__c = null;
      }
      }
      }

      Reply
Orchid
July 7, 2014 @ 9:10 am

Hi David,

I have been following your videos and they are great! I ran into a bit of a snag though with your deduping trigger.

for (Lead l : Trigger.new) {

I am getting an error message that an equal sign was expected.

I’ve tried this into two different Sandboxes and I am getting the same error message.

Any feedback would be appreciated.

Thank you,

Orchid

Reply
    David Liu
    July 7, 2014 @ 9:09 pm

    Post your code and I’ll take a look!

    (Sorry sometimes my site does weird things with code in comments!)

    Reply

Leave a Reply Cancel reply

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


*

*

Theme: Simple Style by Fimply