0

When a contact is updated, i want to know the old value of the owner. This is how I am testing --- Changed Owner on Account, as a result, owner on Contact changed to be the same as Account Owner. The ContactOwner changes as expected however, I am not able to get the value of old ContactOwner.

I am trying to understand why trigger.oldMap gives me the value of new Owner?

    trigger ContactTrigger on Contact (before update) {
     if (Trigger.isBefore) {   
        if (Trigger.isInsert) {
            ContactTriggerHandler handler = new ContactTriggerHandler(Trigger.new);
            handler.beforeInsert();
        } else if (Trigger.isUpdate) {
            ContactTriggerHandler handler = new ContactTriggerHandler(Trigger.new,Trigger.oldMap,Trigger.newMap);
            handler.beforeUpdate();
        }
     }
    }



//**************** Handler Class  ***************** //

    public with sharing class ContactTriggerHandler {
       public List<Contact> contacts;
       public Map<Id,Contact> mapIdVsOldContact;
       public Map<Id,Contact> mapIdVsNewContact;


       public ContactTriggerHandler(List<Contact> triggerNew) {
          this.contacts = triggerNew;
       }

       public ContactTriggerHandler(List<Contact> triggerNew,Map<Id,Contact> mapIdVsOldContact, Map<Id,Contact> mapIdVsNewContact) {
           this.contacts = triggerNew;
           this.mapIdVsOldContact = mapIdVsOldContact;
           this.mapIdVsNewContact = mapIdVsNewContact;

       }

       public void beforeInsert() {
         updateContactOwner();
       }

       public void beforeUpdate() {
         updateContactOwner();

       }


      public void updateContactOwner() {

       Set<Id> accountIds = new Set<Id>();

       for (Contact c : contacts) {
        if (c.AccountId != null) {
            if (!accountIds.contains(c.AccountId)) {
                accountIds.add(c.AccountId);
            }
        }
      }

    Map<Id,Account> accts = new Map<Id,Account>(
        [SELECT OwnerId
         FROM Account
         WHERE Id in :accountIds]);

    for (Contact c : contacts) {

        Contact myoldContact = mapIdVsOldContact.get(c.Id);
        system.debug('My old Contact Owner is ' +myoldContact.OwnerId); // shows new owner
        if (c.AccountId != null && accts.containsKey(c.AccountId)) {
            c.OwnerId = accts.get(c.AccountId).OwnerId;

            system.debug('My New Contact Owner is ' + c.OwnerId); // shows new owner
        }
    }


}  
1
  • 1
    Do you have any other automation on Contact that would make an update on the record? Commented Jan 29, 2020 at 22:52

2 Answers 2

2

I am trying to understand why trigger.oldMap gives me the value of new Owner?

Because changing the Account Owner in the UI causes the Contact Owner to change automatically outside of any trigger context. By the time your trigger runs, the owner is indeed already changed.


Some of your code is not relevant, it could be optimized thusly:

Set<Id> accountIds = new Set<Id>();
for(Contact record: triggerNew) {
  accountIds.add(record.AccountId);
}
Map<Id, Account> accts = new Map<Id, Account>([
  SELECT OwnerId FROM Account WHERE Id = :accountIds
]);
for(Contact record: triggerNew) {
  Account acctRecord = accts.get(record.AccountId);
  if(acctRecord != null) {
    record.OwnerId = acctRecord.OwnerId;
  }
}

This trigger is still possibly handy for the creation of new records, during lead conversion, etc, but the situation you're testing completely makes sense. If you transfer ownership of the contact via an Account Owner change, the new owner will be applied to Contacts owned by the user making the change, as well. No trigger is necessary, and this behavior is expected.

6
  • We had to write a VF page to override the built in owner change functionality for this exact reason.
    – gNerb
    Commented Jan 30, 2020 at 14:35
  • I see! 'Because changing the Account Owner in the UI causes the Contact Owner to change automatically outside of any trigger context.By the time your trigger runs, the owner is indeed already changed.' Thank you,now this makes sense. Does that mean i will not see old Owner? Our Accounts and related contacts are owned by Sales reps. when these are first created,they are owned by 'Guest' we run a batch job to change ownership on Accounts. As a result ownership of Contacts are changed. When this happens i want to create a task for new owner. That's why i am comparing old and new owner value. Commented Jan 30, 2020 at 17:21
  • @user4947 You'd have to instead assign the task as part of the batch process. The old owner will have already changed by the time the trigger fires, as you've observed.
    – sfdcfox
    Commented Jan 30, 2020 at 18:59
  • Thank you. I am sorry, but please can you answer one more question. I said we run batch job to change ownership. ActualIy we change Account ownership via Jitterbit. we have a scheduled job to 'Upsert' Accounts. Many updates happen to the Accounts, some Accounts gets ownership update. That's when the Account trigger kicks in to change ownership on Contact. How should i create a task in this case. ? Commented Jan 30, 2020 at 19:25
  • 1
    @user4947 I'd set the trigger on the Account, then, as that's the only time you'd see the old contact owners.
    – sfdcfox
    Commented Jan 30, 2020 at 19:46
0

I have been trying your trigger and there is something that is not working well. I couldn't see what exactly but take a look to these changes I have done from where you can start building your classes. I don't think you need to add a beforeUpdate(). I will recommend you to check a good trigger framework and perhaps use it as inspiration if you want to build your own.

Ok, I tried this and it works. I have remove parts of the code to narrow down the issue.

Trigger:

trigger ContactTrigger on Contact (before update) {

    if (Trigger.operationType == TriggerOperation.BEFORE_UPDATE) {
        ContactTriggerHandler.updateContactOwner (Trigger.new, Trigger.oldMap, Trigger.newMap);
    }

} 

As you can see I just use Trigger.operationType which is a nice way to control the trigger context.

Service Class:

public with sharing class ContactTriggerHandler {

    public static void updateContactOwner(List<Contact> triggerNew, Map<Id, Contact> mapIdVsOldContact, Map<Id, Contact> mapIdVsNewContact) {

        Set<Id> accountIds = new Set<Id>();

        for (Contact c : triggerNew) {
            if (c.AccountId != null) {
                if (!accountIds.contains(c.AccountId)) {
                    accountIds.add(c.AccountId);
                }
            }
        }
/*
        Map<Id, Account> accts = new Map<Id, Account>(
        [
                SELECT OwnerId
                FROM Account
                WHERE Id IN :accountIds
        ]);
*/
        for (Contact c : triggerNew) {

            Contact myOldContact = mapIdVsOldContact.get(c.Id);
            System.debug('My old Contact Owner is ' + myOldContact.OwnerId); // shows new owner
            //if (c.AccountId != null && accts.containsKey(c.AccountId)) {
            //    c.OwnerId = accts.get(c.AccountId).OwnerId;

                System.debug('My New Contact Owner is ' + c.OwnerId); // shows new owner
            //}
        }
    }

}

As you can see I have remove all to help me narrow down the cause of these problems. That map is not working as expected. I had the code in my org and I tried to change a contact owner and it was not possible. I tried time after time but the contact was not changing.

Try this code and build up or play around with it. It is working now ...

1
  • Carlos thank you for the polite response. Appreciate it. i will test your suggestions and sample code. Commented Jan 30, 2020 at 17:28

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .