You need to sign in to do that
Don't have an account?

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:
|
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
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.
I appologize, but I have no idea what part I need to change.
Would you be able to let me know.
Thank you.
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();
}
}
}
===
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?
Oops, the opty.opty.OwnerId should just be opty.OwnerId. And yeah, you can remove that else, it isn't necessary.
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){
===
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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();
}
}
}
Sorry, should have proofread this before posting it. You just need to add AccountId to the opportunity query in line 7.
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?
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.
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();
}
}
}
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();
}
}
}
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"