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!

Example: How to write a deduping trigger for leads and contacts

October 19, 2013

Preface – This post is part of the Write Your First Intermediate Trigger series.

Ok guys let’s write a trigger that will prevent a user from creating a lead that already exists as a contact! We’ll use the lead/contact’s email address to detect duplicates.

A brilliant person once told me that even the most complicated code can be broken down into tiny, individual steps that are easy to implement. Let’s see what our steps are:

  1. Lead is created or updated
  2. Lead has an email address
  3. Try to find a matching Contact based on email address (using SOQL!)
  4. If a match is found, give the user an error
  5. If a match is not found, do nothing

Now, try to match the steps above with the code! Each step should match to at least one line of code.

trigger FindDupes on Lead (before insert, before update) {
  for (Lead myLead : Trigger.new) {
if (myLead.Email != null) {
List<Contact> dupes = [SELECT Id FROM Contact WHERE Email = :myLead.Email];
if (dupes.size() > 0) {
myLead.Dupe_Contact__c = dupes[0].Id;
} else {
myLead.Dupe_Contact__c = null;
} }
} }

Note that users will receive an error message via a validation rule anytime the Dupe_Contact__c field is populated. Apex is often mixed with point-and-click functionality!

And in case you’ve forgotten…

  • How to read code
  • Where to write code in Salesforce
  • Login to Sfdc99 to see this in action!

Next post: An extended look at our deduping trigger!

115 Comments
Finny
January 5, 2021 @ 4:28 am

@David, this trigger doesn’t work when trying to insert leads using the data loader or API. Can you please help on how to do it?

Reply
    Raju
    April 1, 2021 @ 8:12 pm

    This is one of the interview questions asked how to resolve it as it fails with data loader and works for a single record.

    Reply
siva
August 26, 2017 @ 2:10 am

trigger nelead on Lead (before insert,before update) {
//system.debug(‘the value is’ +add);

list emailids=[select email from Contact where email !=null];
for(Lead Le:trigger.new){

if(Le.email==null){
le.addError(’email address should not be empty’);

}
for (contact con:emailids ){

//if(con.size()>0){

if(le.email ==con.email)

{
le.addError(’email should not be same as contact’);

}
//}
}

}
}

Reply
    siva
    August 26, 2017 @ 2:12 am

    I tried above code .it is working as excepted.Could you check and let me know whether it is correct or not.

    Reply
Sidharth Negi
August 14, 2017 @ 10:13 pm

Hey David,

While the code works for single lead creation, this will be a problem for bulk Lead inserts (SOQL more than 100). I was playing around for bulk check and this works!

Trigger Code:
trigger LeadTrigger on Lead (before insert, before update) {

LeadHandler handler = new LeadHandler();
if (Trigger.isBefore) {
if (Trigger.isInsert) {
handler.onBeforeInsert(Trigger.new);
}
if (Trigger.IsUpdate) {
// handler.onBeforeUpdate(Trigger.new, Trigger.Old);
}
// More event checks if needed
}
}

Handler code:
public class LeadHandler {
Public void onBeforeInsert(List newLeadList) {
Map emailLeadMap = new Map();
for (Lead leadVar : newLeadList) {
emailLeadMap.put(leadVar, leadVar.email);
}
checkDupes(emailLeadMap);
}

private void checkDupes(Map emailLeadMap) {
Map emailContactMap = new Map();
// Get all contacts with matching emails
for (Contact contactVar : [SELECT Email FROM Contact WHERE Email IN :emailLeadMap.values()]) {
// This map can be replaced by Set of emails as well :)
emailContactMap.put(contactVar.email, contactVar);
}
// For every incoming Lead, check if contacts with matching emails were found
for (Lead leadVar : emailLeadMap.keyset()) {
if (emailContactMap.containskey(leadVar.email)) {
leadVar.addError(‘ContactAlreadyExist’);
}
}
}
}

Tested it with Data Import Wizard for about 200 test leads and it allows partial inserts. Pardon my missing comments :)

Reply
    David Liu
    August 15, 2017 @ 9:35 pm

    ^_^ Hi Sid!

    Reply
      Andreas
      August 26, 2017 @ 4:45 am

      Hi David, usually I answer those questions too, but today i have a question about de-Dupe.
      Is there any way we can accomplish the Bulk depupe on behalf of the email using SOSL instead of SOQL,
      Issue i facing is that I can’t use select id, email from contact where email =:’xyz’
      I need to use FIND :’xyz’ in Email fields returning Contact(id,email)

      for a singly user input it is not an issue but on bulk (more than one record) …
      Do you have any idea

      Reply
        David Liu
        August 27, 2017 @ 5:11 pm

        Both work!

        SOSL for multi object, and SOQL for single / few objects =)

        Reply
          Andreas
          August 28, 2017 @ 4:03 am

          But how?
          The trigger is like a list or a map
          Let’s imagine we have the list new contacts
          And we have already filtered out into a map the emails
          Contact I’d , email
          How do I iterate now through the map values aka the email
          Using the Find without having it inside a loop
          I can’t use the where clause on email inside the find
          The find is restricted to 20 call per webcall
          The value I compare is the search string of the find
          Find :searchstr in email fields returning contact(Id,email)
          Where clause is not possible as the email field is encrypted
          I can’t translate the list of email into a joined or string because the searchstr is restricted to 4000 character with containing operator
          Cheers

          Reply
    Gaurav
    April 29, 2018 @ 7:48 am

    Excellent code!

    Reply
Pranil
July 24, 2017 @ 11:58 am

Hi David,
I’m not getting what type of field dupes is?

Reply
abhi
January 8, 2017 @ 3:20 am

Hello David,
I am new to Salesforce. I designed this trigger .[No Custom Object & No Validation ]

trigger FindDupe on Lead (before insert,before update) {

for(Lead myLead:Trigger.new){
if(myLead.Email !=null){

List dupes=[SELECT Id FROM Contact where Email=:myLead.Email];

if(dupes.Size() >0)
myLead.addError(‘Contact with this Email already exits with ID :’+dupes[0].Id);
}
}
}

Reply
Divyendra Naidu
May 25, 2016 @ 2:40 pm

trigger DeDupeLead on Lead (before insert,before update)
{
//Declares a List variable to hold all Contact Id’s, Emails, First and Last Names where the Email is present
List c = [SELECT Id, Email, FirstName, LastName FROM Contact WHERE EMAIL != Null];

//Declares an Integer variable n to hold the size of list c
Integer n = c.size();

//Declares an integer variable for a later For loop
Integer i = 0;

//Creates a loop that passes every lead initiation the trigger to Trigger.new
for (Lead l : Trigger.new)
{
//Loop iterates through every element in the list c
for(i = 0; i < n; i++)
{
//Condition evaluates whether the email of each item in the list c matches that of the lead being created or updated
if(l.Email == c[i].Email)
{
//Fires a validation message if a lead is being created or updated with a duplicate email
l.addError('A duplicate Contact exists'+ c[i].FirstName + ' ' + c[i].LastName);
}
}

}
}

Reply
    Akhil
    October 15, 2016 @ 12:01 am

    This trigger does not complies to best practice. You should not query the entire list of contacts with a filter Email != Null. There is a more chance of hitting the limits.

    Reply
Charu
December 9, 2015 @ 6:46 am

Many Thanks David. Created first trigger. Simply thanks Man.
I am a novice to coding and you have inspired me.

Thanks
Charu

Reply
    David Liu
    December 9, 2015 @ 8:44 pm

    Good job Charu!!

    Reply
mohan
December 1, 2015 @ 12:35 am

trigger Duplicate_email on Contact (before insert) {

list listcon = new list();
List conemail = [select email from contact];
if(trigger.isInsert){
for(Contact con: trigger.new){

for(contact co: conemail){

if(con.Email== co.email && co.email!=null){

con.adderror(‘Please Give valid Email’);

}
}
}
}

}

Reply
Chris (Marzella88)
August 17, 2015 @ 1:19 pm

David,

Are you able to display a custom error message where the user can actually click on the contact id of the duplicate record or at the very least view the contact id?

Reply
    Chris (Marzella88)
    August 17, 2015 @ 1:32 pm

    Never mind David, after searching below I was able to code my own answer! :)

    trigger DupeCheck on Lead (before insert, before update) {

    for(Lead myLead : Trigger.new){
    if(myLead.Email != null){
    List dupes = [SELECT Id FROM Contact WHERE Email = :myLead.Email];

    if(dupes.size() > 0){
    myLead.Duplicate_Record_Found__c = dupes[0].Id;
    //Display Error Message
    myLead.addError(‘There is already a contact with this email address! ‘+ myLead.Duplicate_Record_Found__c);

    }
    else{
    myLead.Duplicate_Record_Found__c = null;
    }
    }

    }

    }

    Reply
      David Liu
      August 17, 2015 @ 6:59 pm

      Well done!

      Reply
        Chris (Marzella88)
        August 18, 2015 @ 1:08 pm

        Thanks David! One additional question though. The code breaks when I try to convert the lead to a contact. (It shows my custom error message) Why is this?

        Reply
          David Liu
          August 18, 2015 @ 7:06 pm

          Are you sure there isn’t a dupe? If not, you might be detecting yourself!

          Reply
            Chris (Marzella88)
            August 19, 2015 @ 5:42 am

            Positive there is no dupe. I tried this with multiple leads. What do you mean by detecting myself?

            Reply
              David Liu
              August 19, 2015 @ 7:12 am

              The Contact created during conversion might be the “dupe”!

              Reply
                Chris (Marzella88)
                August 19, 2015 @ 8:07 am

                Yes, that is definitely what is happening. How do I avoid this from triggering the trigger?

                Reply
                  David Liu
                  August 19, 2015 @ 9:03 pm

                  Oooooo this one is such a good one I can’t tell you or even point you in the right direction. You might not like this answer but it’s so juicy that when you figure it out you can thank me later!!

                  Reply
                    Chris (Marzella88)
                    August 20, 2015 @ 1:25 pm

                    I fixed a small error, but still having the same issue. Here is the updated code. Can I at least get a hint? You’re killing me, lol. By the way, thanks for sticking with me this far. I really appreciate it :)

                    trigger FindDupes on Lead (before insert, before update) {
                    for(Lead myLead : Trigger.new){
                    //create a list of contacts that have an email equal to myLead
                    List dupes = [SELECT Id FROM Contact WHERE Email = :myLead.Email];

                    //check if anything is in the dupes list
                    if(dupes.size() > 0){
                    myLead.Dupe_Contact__c = dupes[0].Id;
                    myLead.addError(‘There is already a contact with this email!’);
                    }
                    else{
                    myLead.Dupe_Contact__c = null;
                    }
                    }
                    }

                    Chris (Marzella88)
                    August 20, 2015 @ 1:28 pm

                    After “List” in the code I have the word “Contact” inside brackets but when I post the comment it deletes the word for some reason.

                    Chris (Marzella88)
                    August 20, 2015 @ 1:46 pm

                    OMG I think this fixes it!

                    if(mylead.ConvertedContactId == null)

                    Is this what you were thinking?

                    David Liu
                    August 20, 2015 @ 6:54 pm

                    That’ll do it!!!!!

                    Worth working hard for right!?! =)

                    Good job Chris!
                    David

                    Chris (Marzella88)
                    August 21, 2015 @ 7:00 am

                    You were right David it was worth it. You’re the man! BTW I attended my first user group meeting last night in Philly and met Steve Molis (he is also the man, lol) Thanks again for your guidance!

                    -Chris

      Anonymous
      October 7, 2016 @ 12:58 pm

      Cheers Chris, was just thinking about this while scrolling through comments!

      Just in case anyone has any errors, I had a couple:

      trigger FindDupes2 on Lead (before insert, before update) {
      for(Lead myLead : Trigger.new){
      if(myLead.Email != null){
      List dupes = [SELECT Id FROM Contact WHERE Email = :myLead.Email];

      if(dupes.size() > 0){
      myLead.Dupe_Contact__c = dupes[0].Id;
      //Display Error Message
      myLead.addError(‘There is already a contact with this email address!’ + myLead.Dupe_Contact__c);

      }
      else{
      myLead.Dupe_Contact__c = null;
      }
      }

      }
      }

      Reply
      Rachel
      April 27, 2017 @ 6:15 pm

      how did you get Duplicate_Record_Found__c. What is it ?

      Reply
Anonymous
July 9, 2015 @ 8:02 pm

HI David,

In your code you are queering inside the for loop. I hope this trigger wont work in bulk insert.

Thanks,
Arjun.

Reply
    David Liu
    July 9, 2015 @ 9:09 pm

    Good call – I cover that in Chapter 5!

    Reply
radha
May 6, 2015 @ 10:00 am

In this chapter trigger ,we are checking for the duplicates in inserted records but what if there are duplicates in the batch of records being inserted.
thanks in advance

Reply
Ravi
March 15, 2015 @ 10:47 am

Hi David

For the below

myLead.Dupe_Contact__c = dupes[0].Id;

Did you add the field Dupe_Contact__c to the Lead object ? It is not there in the sandbox by default ?

Reply
    David Liu
    March 16, 2015 @ 8:13 pm

    Yup – it’s a custom field!

    Reply
Mayank Srivastava
February 8, 2015 @ 5:03 pm

David,
It should be Dupe_Contact__c instead of Contact_Dupe__c in the line just below your code snippet:

“Note that users will receive an error message via a validation rule anytime the Contact_Dupe__c field is populated. Apex is often mixed with point-and-click functionality!”

Reply
    David Liu
    February 8, 2015 @ 5:15 pm

    Fixed, thank you Mayank!

    Reply
    Anonymous
    August 12, 2015 @ 1:47 pm

    its gives error
    Error Error: Compile Error: Invalid field Dupe_Contact__c for SObject Lead at line 7 column 9
    how i solve this error

    Reply
      David Liu
      August 12, 2015 @ 8:22 pm

      Gotta create the custom field!

      Reply
        JB
        July 13, 2016 @ 1:20 am

        Hi David sorry, i am new at this, what kind?

        Reply
Sarvesh
October 27, 2014 @ 11:48 pm

Hi David,

I appreciate your work.

I wanted to know that I have created trigger on events to check if startdatetime field is not either at hours or at half hours round it up.

EXAMPLE : if i select 10.15 am it should round up to 10.30 am and if i select 10.50 So it will round up on 11.00 AM.
But I am not getting as mentioned. My code is below.

trigger EventOnTime on Event (Before Insert, Before Update) {
//SomeClass.setTime(trigger.new);

for(Event so : trigger.new){
if(so.StartDateTime == null ){
continue;
}

if(so.StartDateTime.minute() > 30 ){
so.StartDateTime = so.StartDateTime.addMinutes(60 – so.StartDateTime.minute());
}
else{
so.StartDateTime = so.StartDateTime.addMinutes(30 – so.StartDateTime.minute());
}
}
}

Thanks in Advance

Reply
    David Liu
    October 28, 2014 @ 6:32 pm

    What’s the error message you’re getting?

    Try posting this on the forums you might get a quicker response!
    https://www.sfdc99.com/forums/forum/beginning-apex/

    Reply
    Andreas
    October 29, 2014 @ 3:57 am

    Hi Sarvesh, I didn’t test it but it looks like that you mess up the startDateTime here
    I might be wrong but I would try
    for(Event so : trigger.new){
    if(so.StartDateTime != null ){

    if(so.StartDateTime.minute() > 30 ){
    so.StartDateTime.addMinutes(60 – so.StartDateTime.minute());
    }
    else{
    so.StartDateTime.addMinutes(30 – so.StartDateTime.minute());
    }
    }
    }
    }

    As you are already within the trigger with the current values ( before insert / update)
    the startDateTime is lets say already 11:15
    if you now simply add minutes that should do the trick
    Before you have tried to assign the value of just the minutes to the startDatetime
    so you need to either say
    so.StartDateTime = so.StartDateTime + so.StartDateTime.addMinutes(30 – so.StartDateTime.minute());
    or as I suggest only add the minutes

    Also I changed the IF criteria from == towards != null

    Let me know if that helps

    Reply
NH
September 23, 2014 @ 1:51 pm

Hello David,

Thank you for putting the sfdc99 resource together for guys(/and girls) like me. I am new to coding, thanks to your site (and constant google searches) I feel like I am starting to understand what is apex coding. (Cant say yet that I understand how to code apex, but man it is night and day from before I found this site)

I am currently an Admin and have been trying to find a way to prevent duplicate records with in our salesforce contacts object. I thought I would take a stab at writing code for this and modeled it upon your example found in your beginner lessons.

Here is my logic.

1. Contact record is created or updated
2. Contact record has a Name and Birthdate (and are not empty fields)
3. Try to find a matching Contact based upon Name and Birthdate Fields
4. If a match is found, give the user an error message
5. If a match is not found, do nothing

This is my code:

trigger FindDupes on Contact (before insert, before update) {
for (Contact myContact : Trigger.new) {
if (myContact.Name != null) {
if (myContact.Birthdate != null) {

List dupes = [SELECT Id FROM Contact
WHERE Name = :myContact.Name
AND Birthdate = :myContact.Birthdate];
if (dupes.size() > 0) {
String errorMessage = ‘Duplicate contact found! ‘;
errorMessage += ‘Record ID is ‘ + dupes[0].Id;
myContact.addError(errorMessage);
}
}
}
}
}

I have created a sandbox and added this trigger to the Contacts trigger section. Salesforce accepted the trigger with no error message (it took me many multiple attempts to get no errors), however, when I go to test this code and create several duplicate records – I don’t see an error message when I should, under instances that i create a duplicate contact (name and Birthdate) or anytime I update a record (that is a duplicate record).

Am I missing something or just completely off base? (idk anymore I’ve been staring at my computer screen for hours all weekend trying to figure it out). Any help is greatly appreciated.

Thanks in Advance

-Nate

Reply
    David Liu
    September 25, 2014 @ 7:25 pm

    Great job on the trigger Nate!

    …it actually looks perfect to me!

    My advice is to keep reducing the trigger until it works! (Also, make sure it’s marked as Active).

    For example, try any of these:
    – Just check for an exact Name match (perhaps Last Name instead)
    – Always add an error to the record
    – Use System.debug
    https://www.sfdc99.com/2014/02/22/debug-your-code-with-system-debug/

    Reply
      Andreas
      September 26, 2014 @ 12:58 am

      Hi Nate / David

      I had a quick test and inserted
      system.debug(‘ Name= ‘ + myContact.Name + ‘ bday= ‘ + myContact.Birthdate);
      before and within the IF clause
      and from the debug it looks like that the NAME fields concatenation from Salutation First / Middle / Last name and suffix only
      takes place once the record is saved.

      The debug shows the NAME with a null value,

      therefore you will need to take each single field of the name into account
      so amend your trigger from where Name =: myContact.name
      into where Firstname =: myContact.Firstname AND LastName =: myContact.LastName
      across the whole trigger you might like to add salutation as well

      Hope that helps

      Reply
        NH
        September 26, 2014 @ 3:59 pm

        David (and Andreas),

        Thank you for your reply.

        Let me first say that sfdc99 is awesome. I only found your website here David this past weekend, however, I have become possessed in apex and within a week deployed into my production org my first trigger. My path is just beginning but I already have learned quite a bit so I am grateful for your time and energy creating this resource for the 99%.

        Okay here is what I did;

        Andreas thanks for your advice with Name vs FirstName LastName, it definitely helped. However I still ran into a problem with getting the + 75% coverage needed to deploy. I would at best only get 55%, just changing that aspect of the code. I did some additional research (and David tell me if this comports with your knowledge) as I came up with this after I realized that perhaps binding with a date doesn’t work very well. So the work around was to create a custom formula field called [ of_days_old__c ]. Essentially I created a formula [ TODAY() – Birthdate) ] to turn this date into an integer which would yield a simple ‘primitive’ number. I then bound this expression together [of_days_old__c = :myContact.of_days_old__c ]. After running my test class with only inserting FirstName LastName and Birthdate (not my new custom field to test and see if it works, see test class below) to my surprise I got 100% coverage.

        The following is how my trigger looks now ( all feedback is appreciated)

        trigger FindDupess on Contact (before insert, before update) {

        for (Contact myContact : Trigger.new) {
        if (myContact.LastName != null && myContact.FirstName != null && myContact.Birthdate != null) {
        List dupes = [SELECT Id FROM Contact
        WHERE FirstName = :myContact.FirstName
        AND LastName = :myContact.LastName
        AND of_days_old__c = :myContact.of_days_old__c ] ;
        if (dupes.size() > 0) {
        String errorMessage = ‘Duplicate contact found! ‘;
        errorMessage += ‘Record ID is ‘ + dupes[0].Id;
        myContact.addError(errorMessage);
        }
        }
        }
        }

        the following is how my test class was composed

        @isTest
        public class TestFindDupes {
        static testMethod void testDupes() {
        // Let’s create our records from scratch!
        Contact c = new Contact();
        c.FirstName = ‘Stephen’;
        c.LastName = ‘Curry’;
        c.Birthdate = Date.newInstance(2006, 3, 17);
        insert c;

        // Now let’s create a dupe contact
        Contact dupeContact = new Contact();
        dupeContact.FirstName = ‘Stephen’;
        dupeContact.LastName = ‘Curry’;
        dupeContact.Birthdate = Date.newInstance(2006, 3, 17);
        try {
        insert dupeContact;
        } catch (Exception e) {
        System.debug(‘An error happened, as predicted!’);
        }

        // Now we try to find our dupe contact, by name and dob
        List dupes = [SELECT Id FROM Contact
        WHERE Name = ‘steph curry’
        AND Birthdate = :Date.newInstance(2006, 3, 17)];
        System.assertEquals(0, dupes.size());

        // Now we “break” our trigger by inserting a non-dupe
        Contact legitContact = new Contact();
        legitContact.FirstName = ‘David’;
        legitContact.LastName = ‘Lee’;
        legitContact.Birthdate = Date.newInstance(2007, 3, 17);
        insert legitContact;

        // Now we try to find our legit contact, by name and dob
        List legits = [SELECT Id FROM Contact
        WHERE Name = ‘david lee’
        AND Birthdate = :Date.newInstance(2007, 3, 17)];
        System.assertEquals(1, legits.size());
        }
        }

        David my hats off to you, I modeled both of the above on what you have provided us here on sfdc99. I could not have accomplished this in 5 days ANYWHERE else. Thanks A-Million ( I owe you a case of mikes hard lemonade if/when we ever meet up).

        – Nate

        Reply
          Reshmi
          December 10, 2014 @ 2:03 am

          Hi David,Andreas and NH,

          I tried to implement the same trigger . But, I am getting the error.

          trigger dupcon on Contact (before insert, before update){
          for (Contact c :trigger.new) {
          //c.adderror(‘Hello’);
          if (c.FirstName != null && c.LastName!= null && c.BirthDate!= null) {
          c.adderror(‘Hello’);
          List dupcon = [SELECT Id FROM Contact WHERE FirstName = :c.FirstName AND LastName = :c.LastName ];
          if (dupcon.size() >0 ) {
          String Errmsg = ‘ERROR’;
          Errmsg += ‘Record Id’+dupcon[0].Id;
          c.adderror(Errmsg);
          }
          }
          }
          }
          Seems like the If condition doesn’t work. When i tried to save a duplicate Contact, its getting Saved. I tried to add an error message just before the if statement. Then “hello” appears along with an Error msg saying “Contacts not associated with accounts are private and cannot be viewed by other users or included in reports.” . Thanks in Advance :)

          Reply
            Reshmi
            December 10, 2014 @ 9:39 pm

            Today the above error got disappeared.. :) wow..

            Reply
              David Liu
              December 10, 2014 @ 10:10 pm

              Great job Reshmi!!

              Reply
    Ravi
    March 15, 2015 @ 10:44 am

    Hi Nate

    myContact.addError(errorMessage);

    Where is the method addError impmented ?

    Reply
Ronnie Thomas Jr
August 26, 2014 @ 7:15 pm

Hi David,

I just had a quick question about this line of code from the lead dedupe trigger:

“errorMessage += ‘Record ID is ‘ + dupes[0].Id;”

What does “+=” mean in this line of code?

Reply
    David Liu
    August 27, 2014 @ 10:54 pm

    Great question!

    It’s the same as doing this:

    errorMessage = errorMessage + ‘Record ID is ‘ + dupes[0].Id;

    Basically a shortcut for appending stuff

    Reply
    Andreas
    August 28, 2014 @ 12:49 am

    += is the shortway to express the same as error = error + recordID
    so you can simply write error += recordID

    Reply
      Viru
      August 29, 2014 @ 11:38 pm

      Hi Andreas,

      here += is work – first it add the value and then asign it.
      Like suppose you want to print value 1 to 10 then.
      int a = 0;
      for ( int i =0; i <=10; i++)
      {
      a = a + i;
      // print a here
      }

      And you can also do this like

      a += i;

      Means first add (+) the value and then ( = ) asign it in to a;

      As like this.
      In the above code
      First apend the record id and dupps[0].id then asign this value in to errorMessage.

      I hope it'll help you.

      Regards
      Virendra

      Reply
        Viru
        August 29, 2014 @ 11:57 pm

        Simple consept which you write first that apply first.
        Like if you do
        ” =+ ” then first value is asgin and then add.

        You also can do ” -= “.

        Right David?

        Reply
          David Liu
          September 1, 2014 @ 10:54 pm

          You are 100% right Viru =) Thanks for the clear explanation!

          Reply
Anonymous
August 14, 2014 @ 2:09 am

Hi David,

I wrote this code to update a Email Field Called Data partner Contacts email poc, based on the lookup field MCA data partner poc (look up to a custom object MCA data partner contacts, which has name and email). I want the email address on the child object. the code I wrote is not working, and I am unable to figure out why, can you please help? really appreciate it

trigger UpdateDataPartnerContactEmails on MCA_Campaign__c (After Insert, After update) {

//String x = MCA_Campaign__c.MCA_Data_Partner_Contact__r.Contact_Email__c;
for (MCA_Campaign__c Mca : Trigger.new) {
if (Mca.MCA_Data_Partner_Contact__c != null) {

List Partners = [SELECT Id, Contact_Email__c FROM MCA_Data_Partner_Contacts__c WHERE Name = :Mca.MCA_Data_Partner_Contact__c];

if (Partners.size() > 0){
Mca.Data_Partner_PoC_1_email__c = Partners[0].Contact_Email__c;
update Mca;
}
}
}

}

Reply
    David Liu
    August 14, 2014 @ 9:45 pm

    Use this post to help you figure it out!
    https://www.sfdc99.com/2014/02/22/debug-your-code-with-system-debug/

    Reply
SD
July 21, 2014 @ 9:33 am

David,

Need help to understand this :

Just to check out a requirement i thought of i.e to have a Roll up of Count of Contacts displayed on Account Object.

so i went ahead to create a rollup summary field on Account…but found that in summarized object list contact is not there.

. I have read roll up summary is possible only for master detail relationship, and only for such relationships SF displays an option to create roll up summary. But in here, though it is showing option to create rollup, but not displaying Contact to use.

why so?

Reply
    David Liu
    July 27, 2014 @ 10:05 pm

    Contact to Account is a special type of relationship that doesn’t allow roll-ups =) It’s basically a lookup

    Reply
sandeeep
July 3, 2014 @ 4:20 am

Hi David,

I have usecase, wherein in an opportunity I should be able to add only one product. Could be please tell me how to go about it
Thanks

Reply
    David Liu
    July 3, 2014 @ 10:44 am

    Created a validation rule that makes sure the number of line items is less than 2! No code needed!

    Reply
      Deep
      March 15, 2021 @ 3:41 am

      Can’t this be done in a declarative way : Setup-> Opportunity Setting-> click on checkboxes 1) Prompt users to add product for an opportunity
      2) Once user add the product to an opportunity, user must enter 1
      in the quantity.

      Reply
Kruthi
June 25, 2014 @ 1:15 pm

Hi David,
Not sure if my last comment was received by you, however I continue to go through your blog. Thank you for all your work and my deep respect.
I was trying to implement Lead dedupe the way below using Maps, pls let me know if I am on a right track. Also I am encountering ‘External ID error’, Please advise me on this.

awaiting for your response,

trigger leadDedup on Lead (before insert, before update) {
List conEmailMapLst= [SELECT Id, Name, email from contact];
Map conEmailMap = new map();

for (Contact conList: conEmailMapLst){
conEmailMap.put(conList.Id, conList.email);
}
system.debug(‘Contact Map details—>’+ conEmailMap);

for (Lead lEmail: Trigger.New){
//Going through the Contact email map and verifying if Email exists
if(conEmailMap.containsKey(lEmail.email)){
string errMsg = ‘Email already exists’;
lEmail.addError(errMsg);
}
}
}

Reply
    Viru
    June 25, 2014 @ 11:40 pm

    Hello Kruthi
    i just want to help ! David plz correct me if i am wrong. [ Thanks (-; ]

    okay, So first thing that i observe in your code is that you are using List without defining which type of List.
    1. ) I mean use List instead of List. [on Line number 2]

    And second one is you are using MAP. And same problem with MAP
    2.) Write map conEmailMap = new map(); [On line Number 3]

    Now Third one is you are trying to check this email is exist or not so you use ‘ ContainsKey ‘ method of MAP, But you know that this method is checking only on key of MAP and return True if it Contains.

    3.) You are putting Contact.id on Key side and contact.Email on Value side.so when you using ContainsKey method it check key side and return false because Contact id and email never match.
    So my point is put Contact.Email first and then contact.id like conEmailMap.put( conList.email, conList.Id);
    And then use ContainsKey method.
    It’ll Work.

    Thanks
    Viru (-;

    Reply
      Kruthi
      June 26, 2014 @ 9:52 am

      trigger leadDedup on Lead (before insert, before update) {
      Map conEmailMap = new map();
      List conEmailMapLst= new List();
      conEmailMapLst= [SELECT Id, Name, email from contact];
      for (Contact conList: conEmailMapLst){
      conEmailMap.put(conList.Id, conList.email);
      }
      system.debug(‘Contact Map details—>’+ conEmailMap);

      for (Lead lEmail: Trigger.New){
      if(conEmailMap.containsKey(lEmail.email)){
      string errMsg = ‘Email already exists’;
      lEmail.addError(errMsg);
      }
      }
      }

      So sorry Viru, I had pasted the wrong code :(
      Dont mind pls.
      However i will surely work on your 3rd point.
      Thanks for your inputs.

      Reply
        Kruthi
        June 26, 2014 @ 9:55 am

        I guess there is some problem while posting the commenting even now it shows the same, however my code is
        mapconEmailMap = new map(); and
        List conEmailmapLst = new List();

        Reply
          Kruthi
          June 26, 2014 @ 10:01 am

          The code defining type of Map and List is getting eliminated while comment is posted. Anyways, I am creating a Map of
          Key-> Id, Value-> string ie,
          Key-> Id, Value-> email
          which i will modify as you suggested
          Key-> email, Value-> Id

          Thank you

          Reply
          Viru
          June 26, 2014 @ 11:23 pm

          yeah right there is some problem !

          Reply
        David Liu
        June 26, 2014 @ 9:08 pm

        Thank you Viru and great job so far on the code Kruthi!

        Viru is 100% correct about the Map – you definitely should put the Email in the Key and the Id or Contact in the value!

        One more suggestion I have for you – the first SOQL query can potentially break! If you have a lot of contacts in your database you’ll get an error. So you only need to query contacts that have emails that at least one of your leads has.

        Check this out for more info:
        https://www.sfdc99.com/2014/01/20/soql-queries-inside-loops/

        Reply
    Viru
    June 26, 2014 @ 11:19 pm

    Thank you David (-;

    Reply
    Andreas
    June 26, 2014 @ 11:39 pm

    Hi Kruthi,

    There is another thing I came across, why you only compare the email address? To identify a duplicate you really need to compare the name and the email, because a lot of companies have org wide email addresses means you can have different people from the same company with the same email like info@…..or support @…..

    If you now compare name and email you can stick with the ID as key in the map
    but you would need to use a loop to go through the map

    List conEmailMapLst= [SELECT Id, Name, email from contact];
    Map conEmailMap = new map();

    with

    Map conEmailMap = new Map([SELECT Id, Name, email from contact]);

    Because if you have multiple Names with the same email those wouldn’t be in the map as a map does not allow duplicate keys
    (Sorry to argue with you all on this point)

    for (Lead lEmail: Trigger.New){
    for(Contact c: conEmailMap.values())
    {
    If(lEmail.name == c.Name && lEmail.Email == c.Email)
    {
    string errMsg = ‘Email already exists’;
    lEmail.addError(errMsg);
    }
    }

    this approach is also a highly requirement question

    Lets say your employer is a hospital supplier and every doctor can be a lead
    The doctor has to request any product interest through the company wide address orders@nicehealth.com
    so you can have David , Kruthi, Viru and Andreas ordering products from you with an email orders@nicehealth.com.

    Another sample would be an exhibition about marketing tools. and you get a bunch of business cards
    One company established for their sales personal the company wide address sales@buyonegetonefree.com
    but all some 20 salespeople are interested in your service?

    But if you don’t care about this point, then the best is to use the email as the map key and using the contains key() method.

    Andreas

    Reply
      David Liu
      June 26, 2014 @ 11:41 pm

      Andreas – great note, you are totally correct!

      Reply
      Kruthi
      June 27, 2014 @ 12:13 pm

      Yes Andreas you have a valid point.
      I implemented dedupe in both ways (as per Viru and Andreas inputs) successfully.
      Thank you both for your inputs.

      David surely will consider your suggestion on SOQL as well. Thanks again.
      However i have few questions,

      1) Is it good to have for loop within for ?

      for (Lead lEmail: Trigger.New){
      for(Contact c: conEmailMap.values())
      {
      If(lEmail.name == c.Name && lEmail.Email == c.Email)
      {
      string errMsg = ‘Email already exists’;
      lEmail.addError(errMsg);
      }
      }

      2) Can you pls explain what is an ‘External Entry Id’ error?

      Thank you all once again.

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

        Instead of doing the double for loop, try making the key of you Map c.Name + c.Email =)

        No idea what External Entry ID error is!

        David

        Reply
Mithun Sapui
June 9, 2014 @ 12:12 pm

Hi David
I have a strange issue here . I have written the below deduping trigger based on your webinar. I have defined the Dupe contact fields as a text field and have a validation rule on it. I am getting the error while insert/update with a duplicate email id, but the value of the Id field is not getting populated in the Dupe Contact field. What am I missing here ? (So, I am getting a validation error on the Dupe Contact field but the field itself is blank)

trigger DetectDupes on Contact (before update, before insert) {
for (Contact l : Trigger.new) {
if (l.Email != null) {
String contactEmail = l.Email;
list dupeContacts = [Select Email from Contact
where Email = :contactEmail];
if (dupeContacts.size() > 0) {
l.Dupe_contact__c = dupeContacts[0].Id;
} else {
l.Dupe_contact__c = null;
}
} else {
l.Dupe_contact__c = null;
}
}
}

Reply
    Viru
    June 10, 2014 @ 2:20 am

    Hello Mithun Sapui,

    i think the Dupe_contact__c field is empty because in trigger the record is not committed till you use DML operation like update or insert.
    this trigger work fine but when you assign ” I.Dupe_contact__c = dupeContacts[0].Id ” it’ll assigned but not committed that’s why your text field is still empty when record is duplicated.

    Am i right David ?

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

      Great one Viru, very close! If this was an after trigger you’d be spot on!

      Since it’s a before trigger there is an implied update call automatically at the end of the trigger. It literally means “before update” !

      It’s best if you don’t add the Dupe_Contact__c field to the layout and simply have the error message up on the top of the page. Having the field there doesn’t add any value to the user or the admin. But you’re right that the email address won’t show on that field if the validation rule catches it!

      Reply
        Mithun
        June 11, 2014 @ 7:20 pm

        Thanks so much, David and Viru. I will do it that way.

        Reply
Sanjay
June 2, 2014 @ 2:10 pm

Hi David.

I think ,it is not a good option to write SOQL inside loop. So I modified it. Let me know ,is it right?

trigger DuplicateTrigger on Lead (before insert , before update) {
List leadEmail= new List();
for(Lead l:Trigger.new){
leadEmail.add(l.Email);
}
Integer dupContact=[select count() from Contact where Email=:leadEmail];
for(Lead l:Trigger.new){
if(l.Email!=null){
if(dupContact>0){
l.addError(‘Duplicate lead record ‘);
}
}
}
}

Reply
    David Liu
    June 2, 2014 @ 7:58 pm

    hahaha awesome, great observation! I cover how to do this in chapter 5!

    Reply
Amitabh Sharma
May 5, 2014 @ 9:51 am

Hi David, this is in continuation to my previous reply.

I modified the code with the following to check only when the lead status is not ‘
closed converted’ as this is the status that every lead gets on conversion.

This has fixed the problem for now.

if(leadforDupe.Email != null && leadforDupe.Status ‘Closed – converted’ )

Reply
    David Liu
    May 6, 2014 @ 10:59 pm

    Well done Amitabh!!! Way to hang in there!

    Reply
Amitabh Sharma
May 5, 2014 @ 9:34 am

Hi David, thanks for all the help, I have moved till chapter 7 successfully.

However when i revisited the code on chapter 4, this is working fine if i update an existing Lead record.

When I create a new Lead and try to convert it , again the validation is hit :-(. as the converted contact will have the same email as that of the lead.

thanks in advance.

/*
not lead a new lead create if the contact exists.
Since leads and contacts are not related
*/
trigger SFDC99_Chap4_LeadDedupe on Lead (before insert, before update) {
for(Lead leadforDupe :Trigger.new){
//checking if the lead has an email
if(leadforDupe.Email != null){
//checking the values of the contacts for emails
List dupe = [SELECT Id,LastName,email FROM Contact where email =: leadforDupe.email];
//if email
if(dupe.size() > 0){

leadforDupe.addError(‘Duplicate value on ‘+ dupe[0].id);
}
}
}
}

Reply
Vaishali Singh
April 29, 2014 @ 9:29 am

Hi David,
I know i have been bugging you with my questions. But i am really enjoying coding:
another one for you: I have tried a little different not sure if this is right. I have done this for contact as i am trying on my developer org and all the licences are consumed so instead of using lead i have used contact.
But it is giving error on the user page when i am trying to deactivate the user:
“Review all error messages below to correct your data.
Apex trigger reassignUser caused an unexpected exception, contact your administrator: reassignUser: execution of AfterUpdate caused by: System.DmlException: Update failed. First exception on row 0 with id 0039000000VUI8GAAX; first error: MIXED_DML_OPERATION, DML operation on setup object is not permitted after you have updated a non-setup object (or vice versa): Contact, original object: User: []: Trigger.reassignUser: line 25, column 1
”

I am clueless what this erro is talkinng about.
code snippet:
trigger reassignUser on User (after update)
{
Set userIds = new Set();
List conList= new List();
List oppList= new List();
List updateCon = new List();
for(User loopUser:trigger.new)
{
if(loopUser.IsActive==false)
{
userIds.add(loopUser.id);
}
}
system.debug(‘@@ UserIds @@’+userIds);
conList=[Select id,OwnerId from Contact where OwnerId in: userIds];
system.debug(‘contact list’+conList);
User sysAdmin= [Select id, name from User where name=’Poornima S’];
system.debug(‘@@system admin @@’+sysAdmin);
for(Contact loopCon:conList)
{
loopCon.OwnerId=sysAdmin.id;
system.debug(‘@@ loop contact @@’+loopCon);
updateCon.add(loopCon);
}
update updateCon ;
system.debug(‘@@ contact list @@’+updateCon );
}

Thanks

Reply
    David Liu
    April 29, 2014 @ 8:24 pm

    This one’s a tough one and can go many directions – try Googling the error message and see where that takes you!

    Reply
Vaishali Singh
April 29, 2014 @ 7:30 am

Hi David,
Really thanks for starting this blog. I’ m loving it :)

I used this way of doing the dupeblocker code since i did not want to query inside the for loop as it will query every time the loop is iterated . But i ended up using iterative for loop, which i suppose may be a problem in bulk data. Please suggest how this can be written in a better way.

trigger findDupes on Lead (before insert, before update)
{
List conList = new List();
conList= [Select email,id from Contact];
for(Lead loopLead: Trigger.new)
{
if(loopLead.email!= null)
{
for(Contact loopCon:conList)
{
if(loopLead.email==loopCon.email)
{
String errorMessage = ‘Duplicate contact found! ‘;
errorMessage += ‘Record ID is ‘ + loopCon.Id;
loopLead.addError(errorMessage);
}
}
}
}
}

Cheers!!

Reply
    David Liu
    April 29, 2014 @ 8:22 pm

    Great call!

    You definitely need to check out Chapter 5, as it’s entirely dedicated to answering this question you have!

    Basically, you need to learn the proper way to bulkify =)

    David

    Reply
      Vaishali Singh
      April 30, 2014 @ 9:05 am

      Bravo!! Chapter 5 is amazing. I always had a problem in getting this map thing worked out. But now i have got the clear understanding on this.

      Reply
Mercy Fields
April 22, 2014 @ 2:22 pm

Hi David,

Thank you for your tutorials. I know nothing about coding, so your tutorials are easy to follow. I want to create a trigger that calculates the # of activity per opportunity. The roll-up summary is very limited in Salesforce and I think a trigger would give me the activity count. Please advise. Thanks in advance for your help.

Reply
    David Liu
    April 22, 2014 @ 9:12 pm

    A common trigger!

    Try this:
    1. Create a trigger on Tasks
    2. Create a set of all Opportunities related to Tasks in your trigger
    3. Do one SOQL query to get all Opportunities in #2 and their related tasks
    – https://www.sfdc99.com/2013/06/24/example-how-to-write-a-cross-object-soql-query-part-2/
    4. For each Opportunity, count the number of related tasks!

    You can do it!!!!

    But if you’re lazy, you can just download this:
    https://appexchange.salesforce.com/listingDetail?listingId=a0N30000009i3UpEAI

    =)

    Reply
Sandeep Dharwar
April 21, 2014 @ 12:42 pm

Hi David,

Your explanations are crisp and amazing.Its like no other. I love the way you have structured content.
And you are doing such an amazing job not only helping beginners like me learn but also inspire them which makes Salesforce coding such a joy to learn.I cant thank you enough.

I have a doubt, could you please make me understand these two lines of code
1)List userOpps = [select Id from opportunity
where ownerId = :u.id];
2)for(opportunity x:userOpps){x.ownerId = u.ManagerId;}
I understand that Contact and Account also follow the same pattern.
from Andreas’s post.

Thanks a Million
Sandeep

P.S Dav you are the best

Reply
    David Liu
    April 21, 2014 @ 8:27 pm

    My pleasure!

    The first line is getting a List of all Opportunities that have a specific owner. The second line goes through each of these opps one by one, then changes their owner to the owner’s manager.

    So if I own 5 opps and my manager on my user record is Sandeep, all 5 of my opps will be changed to be owned by Sandeep!

    Hope this helps!
    David

    Reply
Teja
April 16, 2014 @ 1:50 pm

Just to improve upon the great work, you can also use getLevenshteinDistance method to find similar emails too, so for example you can take the string, strip out the domain(to reduce the Levenshtein’s Distance) and see how many similar records are there with a Distance of 2-5 so you can calculate it for user typo’s or different spelling combinations.

Reply
    David Liu
    April 16, 2014 @ 10:28 pm

    Oh my goodness what a wonderful method! Thank you for showing me!

    Reply
Andreas
March 20, 2014 @ 3:18 pm

oki doesn’t work , mixed DML exception (setup / non setup object)

Reply
    David Liu
    March 20, 2014 @ 8:27 pm

    What are you trying to do? =)

    Reply
Anonymous
March 16, 2014 @ 9:52 am

Hi David,
Once again — great site — I am really enjoying your work; not just the lessons but the entire site structure and how you have it tied in with WordPress – slick stuff. I am impressed with your energy level! Keep it going! :)

In regard to the code example above and to make sure that I am not misunderstanding things that I thought I knew and continue to learn — would you say that the SELECT query on the contacts should not be inside the trigger.new loop? Would it be best to some how get a map of the contacts prior to the trigger loop? Am I wrong or are you building us up to that and want to keep the lessons learned as basic as possible?

I just want to make sure I am staying on the right track so I appreciate your feedback.

Tom B.

Reply
    David Liu
    March 16, 2014 @ 9:26 pm

    Excellent observation Tom!

    I’m building the user up at this point =) You’ll want to zip to Chapter 5 for tutorials on bulkifying code!

    David

    Reply
Rajesh Kumar
February 12, 2014 @ 3:10 am

But above trigger is not working in case of convert lead. So do you have any other way to implement convert Lead also.

Reply
    David Liu
    February 12, 2014 @ 7:01 pm

    This will work when the lead is inserted/updated – so it runs before the lead conversion, which is even better!!

    Reply
Graham
December 6, 2013 @ 6:18 am

Hi David,

Not sure if you received my last comment as it does not appear to have posted. I wanted to thank you for providing the most easy to understand tutorials for beginners trying to learn apex. Please keep on posting. Also, could you possibly send me some intermediate sample trigger exercises (like the deduping one) so that I can try to create them? I would really appreciate it. I am getting to grips with Apex at a phenomenal rate thanks to this site.

Thank you
Graham

Reply
    David Liu
    December 7, 2013 @ 10:51 am

    Here’s another trigger to try:

    Write a trigger that reassigns all of a User’s leads, accounts, contacts, and opportunities when he/she is deactivated!

    David

    Reply
      Keith Larsen
      December 20, 2013 @ 9:11 am

      Hi David, you explanations are the best I’ve ever seen, keep up the great work. I wrote the trigger you suggested that that reassigns all of a User’s leads, accounts, contacts, and opportunities when he/she is deactivated and wanted you to see if I did it correctly.

      trigger ReassignUserRecs on User (after update) {
      for (User u : trigger.new ){
      If (u.isActive = true) {
      List userLeads = [select Id from lead
      where ownerId = :u.id];

      List userContact = [select Id from contact
      where ownerId = :u.id];

      List userOpps = [select Id from opportunity
      where ownerId = :u.id];

      If (userLeads != null && userLeads.size() > 0){
      for (Integer i = 0; i 0){
      for (Integer i = 0; i 0){
      for (Integer i = 0; i <= userOpps.size() -1; i++){
      // reassign owner to sys admin
      userOpps[i].ownerId = '00570000001LL9';
      }
      update userOpps;
      }

      }
      }
      }

      Reply
        David Liu
        December 22, 2013 @ 10:27 pm

        Awesome stuff Keith, you are very close! This is incredibly impressive!

        Here are some potential areas of improvement:
        – I think there is a small error in that you run the trigger if a User is active instead of inactive!
        – This may be something wrong with the way comments work on this site, but some of your code might be cut off. I’m talking about the area where you check if leads exists, then iterate across each to reassign them. Ditto for contacts as well! Try re-pasting those lines and I’ll let you know if they look good.

        David

        Reply
          Andreas
          March 20, 2014 @ 3:09 pm

          Looks this better ? , but not bulkified

          trigger ReassignUserRecs on User (after update) {
          for (User u : trigger.new ){
          If (!u.isActive) {
          List userLeads = [select Id from lead
          where ownerId = :u.id];

          List userContact = [select Id from contact
          where ownerId = :u.id];

          List userOpps = [select Id from opportunity
          where ownerId = :u.id];

          List userAccount = [select Id from Account
          where ownerId = :u.id];

          for(Lead x:userLeads){x.ownerId = u.ManagerId;}
          for(contact x:userContact){x.ownerId = u.ManagerId;}
          for(opportunity x:userOpps){x.ownerId = u.ManagerId;}
          for(Account x:userAccount){x.ownerId = u.ManagerId;}

          update userLeads;
          update userContact;
          update userOpps;
          update useraccount;
          }
          }
          }

          Reply
      Srinivas
      April 18, 2014 @ 11:08 pm

      Hey David,

      Please explain that question once again..if u dont mind…i didnt understand the meaning of term “deactivated”….

      Thanks,
      Srinivas.

      Reply
        David Liu
        April 19, 2014 @ 12:00 am

        By deactivated I simply mean the “Active” checkbox on the User is unchecked =)

        But even better than this, try this quiz for this chapter (answers are posted as well)
        https://www.sfdc99.com/2014/02/01/quiz-chapter-4/

        Reply
          Faraz Mohammad Khan
          December 18, 2014 @ 1:55 am

          Hi David,

          I tried my hand on writing the reassignment trigger. Below is the code

          trigger ReassignRecords on User (after update) {

          List accounts = [Select Id from Account where ownerId in: Trigger.new];
          List contacts = [Select Id from Contact where ownerId in: Trigger.new];
          List leads = [Select Id from Lead where ownerId in: Trigger.new];
          List opportunities = [Select Id from Opportunity where ownerId in: Trigger.new];

          for(User u : Trigger.new){
          if(u.isActive == false){
          for(Account a : accounts){
          a.ownerId = ‘00590000002jyDnAAI’;
          }
          for(Contact c : contacts){
          c.ownerId = ‘00590000002jyDnAAI’;
          }
          for(Lead l : leads){
          l.ownerId = ‘00590000002jyDnAAI’;
          }
          for(Opportunity o : opportunities){
          o.ownerId = ‘00590000002jyDnAAI’;
          }
          }
          }
          update leads;
          update opportunities;
          update accounts;
          update contacts;
          }

          The code compiles successfully. The thing is whenever I try to test it by making a user inactive, I get this error
          MIXED_DML_OPERATION, DML operation on setup object is not permitted after you have updated a non-setup object (or vice versa): Lead, original object: User

          I did some goggling and found out that its some sort of logical compartmentalization that Salesforce does by considering user as setup object and the rest of my concerned object as non-setup object. Also the answers community suggested that I use @future annotation to work around this.
          I have some info about @future annotation but I would love to know what you thin about this.

          Thanks :)

          Reply
            David Liu
            December 18, 2014 @ 8:46 pm

            @future isn’t a bad solution but I wonder if you’d have better results using a before update?

            Now that you mention it, I’m going to do a post on @future!

            David

            Reply
              Andreas
              December 19, 2014 @ 12:06 am

              “Now that you mention it, I’m going to do a post on @future!”

              good idea, please do not forget about the implications of the @future / trigger (arguments) and @future and batch

              Reply

Leave a Reply Cancel reply

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


*

*

Theme: Simple Style by Fimply