+ Start a Discussion
Joe BBJoe BB 

System.NullPointerException: Attempt to de-reference a null object

Hello,

I have the following trigger that is designed to change an Opportunity owner to a new account owenr after an account DLoader upsert. It compares the owners of Opportunity to new owenrs of accounts and users who share accounts (indicated by UserID inserted in SLS2__c upon account update).

 

The trigger works when I change account owners manually in SFDC, but does not work wehn I use that DataLoader to update ownership. It returns the following ERROR:

updateOppOwner: execution of AfterUpdate

caused by: System.NullPointerException: Attempt to de-reference a null object

Trigger.updateOppOwner: line 17, column 1.

 

Please help.

this is the trigger inserted in Account:Triggers

====

 

Line 17 : optyMap.get(acct.id).OwnerID= acct.OwnerID;

======

Full trigger:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

 

trigger updateOppOwner on Account (after insert, after update) {
  if (Trigger.isAfter) {
  Set<Id> acctIds = new Set<Id>();
    for (Account acct : Trigger.new) {
       acctIds.add(acct.Id);
       }     
Map<id,Opportunity> optyMap = new Map<Id,Opportunity>( [SELECT OwnerId  FROM Opportunity WHERE AccountId in :acctIds]);

    if ( !optyMap.isEmpty() ) {

    for (Account acct : Trigger.new) {

        for(Opportunity opty : optyMap.values() ) {      

            if(opty.OwnerId != acct.OwnerId && opty.OwnerId != acct.SLS2__c){

               optyMap.get(acct.id).OwnerID= acct.OwnerID;
                    } else {
          opty.OwnerId = opty.OwnerId ;
                   }
            }

        update optyMap.values();

        }
  }
    }
    }

Best Answer chosen by Admin (Salesforce Developers) 
ICSteveICSteve

Try this:

 

trigger updateOppOwner on Account (after insert, after update) {
if (Trigger.isAfter) {
Set<Id> acctIds = new Set<Id>();
for (Account acct : Trigger.new) {
acctIds.add(acct.Id);
}
Map<id,Opportunity> optyMap = new Map<Id,Opportunity>( [SELECT AccountId,OwnerId FROM Opportunity WHERE AccountId in :acctIds]);
if ( !optyMap.isEmpty() ) {
for (Account acct : Trigger.new) {

for(Opportunity opty : optyMap.values() ) {
if(opty.AccountId == acct.Id && opty.OwnerId != acct.OwnerId && opty.OwnerId != acct.SLS2__c){
optyMap.get(opty.Id).OwnerID= acct.OwnerID;
} else {
opty.OwnerId = opty.OwnerId ;    // Why are you doing this?
}
}
}
update optyMap.values();
}
}
}

All Answers

ICSteveICSteve

You are using the account id to access the opportunity in optyMap, you need to use opty.Id.

You also need to add a check to make sure the opportunity belongs to the current account, otherwise all opportunities will end up with the owner of the last account in the list.

Joe BBJoe BB

I appologize, but I have no idea what part I need to change.

Would you be able to let me know.

 

Thank you.

ICSteveICSteve

Try this:

 

trigger updateOppOwner on Account (after insert, after update) {
if (Trigger.isAfter) {
Set<Id> acctIds = new Set<Id>();
for (Account acct : Trigger.new) {
acctIds.add(acct.Id);
}
Map<id,Opportunity> optyMap = new Map<Id,Opportunity>( [SELECT AccountId,OwnerId FROM Opportunity WHERE AccountId in :acctIds]);
if ( !optyMap.isEmpty() ) {
for (Account acct : Trigger.new) {

for(Opportunity opty : optyMap.values() ) {
if(opty.AccountId == acct.Id && opty.OwnerId != acct.OwnerId && opty.OwnerId != acct.SLS2__c){
optyMap.get(opty.Id).OwnerID= acct.OwnerID;
} else {
opty.OwnerId = opty.OwnerId ;    // Why are you doing this?
}
}
}
update optyMap.values();
}
}
}

This was selected as the best answer
Joe BBJoe BB
It returns the following error upon saving the trigger:
Error: Compile Error: Invalid foreign key relationship: Opportunity.opty at line 12 column 33 

===

Line 12: if(opty.AccountId == acct.Id && opty.opty.OwnerId != acct.OwnerId && opty.OwnerId != acct.SLS2__c){L

===

 

 

 

} else {
opty.OwnerId = opty.OwnerId ;    // Why are you doing this?

Is that something that I can go without?

ICSteveICSteve

Oops, the opty.opty.OwnerId should just be opty.OwnerId. And yeah, you can remove that else, it isn't necessary.

Joe BBJoe BB

It saved good. However, upon Account ownership update it returned the following:

updateOppOwner: execution of AfterUpdate

caused by: System.SObjectException: SObject row was retrieved via SOQL without querying the requested field: Opportunity.AccountId

Trigger.updateOppOwner: line 12, column 1

 

This is the trigger:

I removed the else statement. Not sure about the number of curly brackets, but it saved OK.

 

===

Line 12 : if(opty.AccountId == acct.Id && opty.OwnerId != acct.OwnerId && opty.OwnerId != acct.SLS2__c){

===

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
trigger updateOppOwner on Account (after insert, after update) {
if (Trigger.isAfter) {
Set<Id> acctIds = new Set<Id>();
for (Account acct : Trigger.new) {
acctIds.add(acct.Id);
}
Map<id,Opportunity> optyMap = new Map<Id,Opportunity>( [SELECT OwnerId FROM Opportunity WHERE AccountId in :acctIds]);
if ( !optyMap.isEmpty() ) {
for (Account acct : Trigger.new) {

for(Opportunity opty : optyMap.values() ) {
if(opty.AccountId == acct.Id && opty.OwnerId != acct.OwnerId && opty.OwnerId != acct.SLS2__c){
optyMap.get(opty.Id).OwnerID= acct.OwnerID;
}
}
}
update optyMap.values();
}
}
}
ICSteveICSteve

Sorry, should have proofread this before posting it. You just need to add AccountId to the opportunity query in line 7.

Joe BBJoe BB
Like this ? Map optyMap = new Map( [SELECT OwnerId FROM Opportunity WHERE AccountId in :acctIds]); Thanks!
ICSteveICSteve
Map<id,Opportunity> optyMap = new Map<Id,Opportunity>( [SELECT AccountId,OwnerId FROM Opportunity WHERE AccountId in :acctIds]);
Joe BBJoe BB

Dancing

 

Works!!!!!!!!!!!!!!!

 

Thank you so much. In my next post I will explain why I need the trigger for the record.

 

Do you think that I can use that trigger with upserting 70,000 accounts. Just few of them will have opportunities, but my concern is: Is there any kind of restriction on trigger calls? 

ICSteveICSteve

Yeah, this should work fine for any number of records. The only problem when working with large sets of records is ensuring that you don't go over your SOQL limits. This will be fine for that though, I moved the updating out of the loop so that it will only be executed once.

Joe BBJoe BB

Explanation:

SFDC  provides visibility to accounts and their child objects when a prior account owner has Opportunities, Contacts or Cases left attached to a prior account.

 

In my organization, we do not want account owners to have visibility and run reports over accounts that they do not currently own.

One solution was to export Opps and Contacts after each Account ownership update and check whether Opps and Contact ow-ship needs to be updated as well. This adds to the update procedures which are too many as of now anyway.

 

So, we want to use trigger that automatically checks this for us.

 

After an account update, the trigger needs to pick up all opportunities and check each opp whether its current owner is the same as the account owner to which this opp pertains.

 

In addition, it needs to check if the Current opp OwnerID is the same as the one of the UserIDs inserted in account SLS2__c custom field (which is updated upon account update as well). SLS2_c  is the ID of a user that shares the account  and is allowed to have opportunities attached the account and have visibility over the account.

 

So, the trigger checks for these conditions after account update. If Opp owner is not the NEW Acc owner or a shared Acc user, then it changes the Opp owner to the New Acc owner.

 

In this way prior owners will be prevented from having access to accounts that they are not supposed to see and run reports on.

 

This is the working trigger:

Thank you again Steve!

 

Now I have to come up with the same trigger for acc. I will try to just rename Opps. O.O

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

trigger updateOppOwner on Account (after insert, after update) {
if (Trigger.isAfter) {
Set<Id> acctIds = new Set<Id>();
for (Account acct : Trigger.new) {
acctIds.add(acct.Id);
}
Map<id,Opportunity> optyMap = new Map<Id,Opportunity>( [SELECT AccountId,OwnerId FROM Opportunity WHERE AccountId in :acctIds]); 
if ( !optyMap.isEmpty() ) {
for (Account acct : Trigger.new) {

for(Opportunity opty : optyMap.values() ) {
if(opty.AccountId == acct.Id && opty.OwnerId != acct.OwnerId && opty.OwnerId != acct.SLS2__c){
optyMap.get(opty.Id).OwnerID= acct.OwnerID;
}
}
}
update optyMap.values();
}
}
}

 

Joe BBJoe BB

The Contact Trigger works as well!!!

 

Thank you so much again, Steve!

You made my day!

 

It is amazing how few lines of text can simplify so much ones life.

 

This is the trigger for Contact:

====

trigger updateContactOwner on Account (after insert, after update) {
if (Trigger.isAfter) {
Set<Id> acctIds = new Set<Id>();
for (Account acct : Trigger.new) {
acctIds.add(acct.Id);
}
Map<id,Contact> ContactMap = new Map<Id,Contact>( [SELECT AccountId,OwnerId FROM Contact WHERE AccountId in :acctIds]);
if ( !ContactMap.isEmpty() ) {
for (Account acct : Trigger.new) {

for(Contact Contact : ContactMap.values() ) {
if(Contact.AccountId == acct.Id && Contact.OwnerId != acct.OwnerId && Contact.OwnerId != acct.SLS2__c){
ContactMap.get(Contact.Id).OwnerID= acct.OwnerID;
}
}
}
update ContactMap.values();
}
}
}

cbrocbro

I am getting the same error, 

 

I am trying to put the Contract Id into a Lookup field on the Account.

 

(Account.Contract_Lookup__c).

 

What am I missing?

 

"ContractNumberOnAccount: execution of BeforeUpdate caused by: System.NullPointerException: Attempt to de-reference a null object: Trigger.ContractNumberOnAccount: line 20, column 1"

 

trigger ContractNumberOnAccount on Contract (before insert, before update) {

{
    Map <Id, Contract> oldmap = new Map <Id, Contract>();
    Map <Id, Contract> newmap = new Map <Id, Contract>();
    List <Account> newAccountList = new List <Account>();
 
 System.debug('------ Contract First Run-----------'+Constants.Contract_First_Run);

    if(Constants.CONTRACT_FIRST_RUN)  
    {
        Map<Id, Account> accountMap = new Map<Id, Account>();

        for(Contract c: Trigger.new) 
        {
            if(c.Status <> 'Expired') // Contract has an Account record and is Expired.
            {
                Account a = accountMap.get(c.Id);

                a.ContractLookup__c = c.Id;
                newAccountList.add(a);
            }
            
        }
        Constants.CONTRACT_FIRST_RUN = False;
        if(newAccountList.size()>0)
    {
    //System.debug('Chris has values to insert = '+ newConList.size());
    try
     {
        upsert newAccountList;
     }
     catch (System.Dmlexception e)  
     {
        system.debug (e); 
     }
}    }
}
}