Cannot move query outside of FOR loop?
Clash Royale CLAN TAG#URR8PPP
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;
up vote
1
down vote
favorite
REQUIREMENT: Need to move the query outside of the FOR loop in Opportunity trigger.
PROBLEM: After moving query outside of the FOR loop, I receive an error when trying to save a new Opportunity record (when it is triggered).
Original Code (no issues):
trigger myTrigger on Opportunity (before insert)
Set<Id> parentAccountIds = new Set<Id>();
for(Opportunity opp : Trigger.new)
parentAccountIds.add(opp.AccountId);
//query fields on parent accounts and map them by Account Id
Map<Id, Account> parentAccountsById = new Map<Id, Account>([
select Id, CustomField__c
from Account
where Id in :parentAccountIds
]);
if(String.isNotBlank(opp.AccountId))
Date CustomField = parentAccountsById.get(opp.AccountId).CustomField__c;
// do stuff
Code after moving the query, has error (see below):
trigger myTrigger on Opportunity (before insert)
Set<Id> parentAccountIds = new Set<Id>();
//query fields on parent accounts and map them by Account Id
Map<Id, Account> parentAccountsById = new Map<Id, Account>([
select Id, CustomField__c
from Account
where Id in :parentAccountIds
]);
for(Opportunity opp : Trigger.new)
parentAccountIds.add(opp.AccountId);
if(String.isNotBlank(opp.AccountId))
Date CustomField = parentAccountsById.get(opp.AccountId).CustomField__c;
// do stuff
ERROR:
myTrigger: execution of BeforeInsert caused by:
System.NullPointerException: Attempt to de-reference a null object
Trigger.myTrigger: line 22, column 1
LINE 22 refers TO:
Date CustomField = parentAccountsById.get(opp.AccountId).CustomField__c;
apex trigger soql class for
add a comment |
up vote
1
down vote
favorite
REQUIREMENT: Need to move the query outside of the FOR loop in Opportunity trigger.
PROBLEM: After moving query outside of the FOR loop, I receive an error when trying to save a new Opportunity record (when it is triggered).
Original Code (no issues):
trigger myTrigger on Opportunity (before insert)
Set<Id> parentAccountIds = new Set<Id>();
for(Opportunity opp : Trigger.new)
parentAccountIds.add(opp.AccountId);
//query fields on parent accounts and map them by Account Id
Map<Id, Account> parentAccountsById = new Map<Id, Account>([
select Id, CustomField__c
from Account
where Id in :parentAccountIds
]);
if(String.isNotBlank(opp.AccountId))
Date CustomField = parentAccountsById.get(opp.AccountId).CustomField__c;
// do stuff
Code after moving the query, has error (see below):
trigger myTrigger on Opportunity (before insert)
Set<Id> parentAccountIds = new Set<Id>();
//query fields on parent accounts and map them by Account Id
Map<Id, Account> parentAccountsById = new Map<Id, Account>([
select Id, CustomField__c
from Account
where Id in :parentAccountIds
]);
for(Opportunity opp : Trigger.new)
parentAccountIds.add(opp.AccountId);
if(String.isNotBlank(opp.AccountId))
Date CustomField = parentAccountsById.get(opp.AccountId).CustomField__c;
// do stuff
ERROR:
myTrigger: execution of BeforeInsert caused by:
System.NullPointerException: Attempt to de-reference a null object
Trigger.myTrigger: line 22, column 1
LINE 22 refers TO:
Date CustomField = parentAccountsById.get(opp.AccountId).CustomField__c;
apex trigger soql class for
add a comment |
up vote
1
down vote
favorite
up vote
1
down vote
favorite
REQUIREMENT: Need to move the query outside of the FOR loop in Opportunity trigger.
PROBLEM: After moving query outside of the FOR loop, I receive an error when trying to save a new Opportunity record (when it is triggered).
Original Code (no issues):
trigger myTrigger on Opportunity (before insert)
Set<Id> parentAccountIds = new Set<Id>();
for(Opportunity opp : Trigger.new)
parentAccountIds.add(opp.AccountId);
//query fields on parent accounts and map them by Account Id
Map<Id, Account> parentAccountsById = new Map<Id, Account>([
select Id, CustomField__c
from Account
where Id in :parentAccountIds
]);
if(String.isNotBlank(opp.AccountId))
Date CustomField = parentAccountsById.get(opp.AccountId).CustomField__c;
// do stuff
Code after moving the query, has error (see below):
trigger myTrigger on Opportunity (before insert)
Set<Id> parentAccountIds = new Set<Id>();
//query fields on parent accounts and map them by Account Id
Map<Id, Account> parentAccountsById = new Map<Id, Account>([
select Id, CustomField__c
from Account
where Id in :parentAccountIds
]);
for(Opportunity opp : Trigger.new)
parentAccountIds.add(opp.AccountId);
if(String.isNotBlank(opp.AccountId))
Date CustomField = parentAccountsById.get(opp.AccountId).CustomField__c;
// do stuff
ERROR:
myTrigger: execution of BeforeInsert caused by:
System.NullPointerException: Attempt to de-reference a null object
Trigger.myTrigger: line 22, column 1
LINE 22 refers TO:
Date CustomField = parentAccountsById.get(opp.AccountId).CustomField__c;
apex trigger soql class for
REQUIREMENT: Need to move the query outside of the FOR loop in Opportunity trigger.
PROBLEM: After moving query outside of the FOR loop, I receive an error when trying to save a new Opportunity record (when it is triggered).
Original Code (no issues):
trigger myTrigger on Opportunity (before insert)
Set<Id> parentAccountIds = new Set<Id>();
for(Opportunity opp : Trigger.new)
parentAccountIds.add(opp.AccountId);
//query fields on parent accounts and map them by Account Id
Map<Id, Account> parentAccountsById = new Map<Id, Account>([
select Id, CustomField__c
from Account
where Id in :parentAccountIds
]);
if(String.isNotBlank(opp.AccountId))
Date CustomField = parentAccountsById.get(opp.AccountId).CustomField__c;
// do stuff
Code after moving the query, has error (see below):
trigger myTrigger on Opportunity (before insert)
Set<Id> parentAccountIds = new Set<Id>();
//query fields on parent accounts and map them by Account Id
Map<Id, Account> parentAccountsById = new Map<Id, Account>([
select Id, CustomField__c
from Account
where Id in :parentAccountIds
]);
for(Opportunity opp : Trigger.new)
parentAccountIds.add(opp.AccountId);
if(String.isNotBlank(opp.AccountId))
Date CustomField = parentAccountsById.get(opp.AccountId).CustomField__c;
// do stuff
ERROR:
myTrigger: execution of BeforeInsert caused by:
System.NullPointerException: Attempt to de-reference a null object
Trigger.myTrigger: line 22, column 1
LINE 22 refers TO:
Date CustomField = parentAccountsById.get(opp.AccountId).CustomField__c;
apex trigger soql class for
apex trigger soql class for
edited Nov 16 at 23:09
Sebastian Kessel
8,51052136
8,51052136
asked Nov 16 at 22:24
paulK
487
487
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
up vote
3
down vote
The answer by the OP does solve the problem, but I'd like to go into more detail about why it works (and why the initial attempt didn't work).
Let's take the bottom-most loop over Trigger.new
for(Opportunity opp : Trigger.new)
if(String.isNotBlank(opp.AccountId))
Date CustomField = parentAccountsById.get(opp.AccountId).CustomField__c;
// do stuff
The if
statement ensures that our Opportunity
does indeed have an AccountId
, but we can still run into a Null Pointer Exception (NPE).
Without performing some sort of null check on the map (or result), parentAccountsById.get(opp.AccountId)
can return null
.
null.<anything>
results in an NPE, because null
has no properties, variables, or methods.
Looking at OP's full first attempt (with my own comments):
trigger myTrigger on Opportunity (before insert)
// This line both declares and initializes parentAccountIds
// This allows us to use the standard set methods, but the set is empty
Set<Id> parentAccountIds = new Set<Id>();
// In this query, we haven't put anything into parentAccountIds
// This query will thus return 0 rows, but still give us our initialization
// for the map parentAccountsById.
// We can call any standard method of the Map class, but the map will contain nothing
Map<Id, Account> parentAccountsById = new Map<Id, Account>([
select Id, CustomField__c
from Account
where Id in :parentAccountIds
]);
for(Opportunity opp : Trigger.new)
// We're adding accountIds to the parentAccountIds set _after_ running
// the query
parentAccountIds.add(opp.AccountId);
if(String.isNotBlank(opp.AccountId))
// The opp's AccountId is not blank, but because we have nothing in
// parentAccountsById, we end up trying to call null.CustomField__c
// which results in an NPE
Date CustomField = parentAccountsById.get(opp.AccountId).CustomField__c;
// do stuff
The solution, as illustrated by paulK, is to use the following pattern:
- Declare/initialize a collection
- Iterate over
Trigger.new
, and add the Ids to the collection - Perform a query, using the collection of Ids gathered previously
- Iterate over
Trigger.new
again, this time doing the work you want to actually do
Again, the key part of this pattern is that we iterate twice over Trigger.new
. We need to gather the Ids we want to use in the query before we execute the query.
Nice explanation, Derek! Have an upvote!
– paulK
Nov 16 at 23:25
add a comment |
up vote
1
down vote
Ok, found the solution...
trigger myTrigger on Opportunity (before insert)
Set<Id> parentAccountIds = new Set<Id>();
for(Opportunity newOpp : Trigger.new)
parentAccountIds.add(newOpp.AccountId);
//query fields on parent accounts and map them by Account Id
Map<Id, Account> parentAccountsById = new Map<Id, Account>([
select Id, CustomField__c
from Account
where Id in :parentAccountIds
]);
for(Opportunity opp : Trigger.new)
if(String.isNotBlank(opp.AccountId))
Date CustomField = parentAccountsById.get(opp.AccountId).CustomField__c;
// do stuff
add a comment |
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
3
down vote
The answer by the OP does solve the problem, but I'd like to go into more detail about why it works (and why the initial attempt didn't work).
Let's take the bottom-most loop over Trigger.new
for(Opportunity opp : Trigger.new)
if(String.isNotBlank(opp.AccountId))
Date CustomField = parentAccountsById.get(opp.AccountId).CustomField__c;
// do stuff
The if
statement ensures that our Opportunity
does indeed have an AccountId
, but we can still run into a Null Pointer Exception (NPE).
Without performing some sort of null check on the map (or result), parentAccountsById.get(opp.AccountId)
can return null
.
null.<anything>
results in an NPE, because null
has no properties, variables, or methods.
Looking at OP's full first attempt (with my own comments):
trigger myTrigger on Opportunity (before insert)
// This line both declares and initializes parentAccountIds
// This allows us to use the standard set methods, but the set is empty
Set<Id> parentAccountIds = new Set<Id>();
// In this query, we haven't put anything into parentAccountIds
// This query will thus return 0 rows, but still give us our initialization
// for the map parentAccountsById.
// We can call any standard method of the Map class, but the map will contain nothing
Map<Id, Account> parentAccountsById = new Map<Id, Account>([
select Id, CustomField__c
from Account
where Id in :parentAccountIds
]);
for(Opportunity opp : Trigger.new)
// We're adding accountIds to the parentAccountIds set _after_ running
// the query
parentAccountIds.add(opp.AccountId);
if(String.isNotBlank(opp.AccountId))
// The opp's AccountId is not blank, but because we have nothing in
// parentAccountsById, we end up trying to call null.CustomField__c
// which results in an NPE
Date CustomField = parentAccountsById.get(opp.AccountId).CustomField__c;
// do stuff
The solution, as illustrated by paulK, is to use the following pattern:
- Declare/initialize a collection
- Iterate over
Trigger.new
, and add the Ids to the collection - Perform a query, using the collection of Ids gathered previously
- Iterate over
Trigger.new
again, this time doing the work you want to actually do
Again, the key part of this pattern is that we iterate twice over Trigger.new
. We need to gather the Ids we want to use in the query before we execute the query.
Nice explanation, Derek! Have an upvote!
– paulK
Nov 16 at 23:25
add a comment |
up vote
3
down vote
The answer by the OP does solve the problem, but I'd like to go into more detail about why it works (and why the initial attempt didn't work).
Let's take the bottom-most loop over Trigger.new
for(Opportunity opp : Trigger.new)
if(String.isNotBlank(opp.AccountId))
Date CustomField = parentAccountsById.get(opp.AccountId).CustomField__c;
// do stuff
The if
statement ensures that our Opportunity
does indeed have an AccountId
, but we can still run into a Null Pointer Exception (NPE).
Without performing some sort of null check on the map (or result), parentAccountsById.get(opp.AccountId)
can return null
.
null.<anything>
results in an NPE, because null
has no properties, variables, or methods.
Looking at OP's full first attempt (with my own comments):
trigger myTrigger on Opportunity (before insert)
// This line both declares and initializes parentAccountIds
// This allows us to use the standard set methods, but the set is empty
Set<Id> parentAccountIds = new Set<Id>();
// In this query, we haven't put anything into parentAccountIds
// This query will thus return 0 rows, but still give us our initialization
// for the map parentAccountsById.
// We can call any standard method of the Map class, but the map will contain nothing
Map<Id, Account> parentAccountsById = new Map<Id, Account>([
select Id, CustomField__c
from Account
where Id in :parentAccountIds
]);
for(Opportunity opp : Trigger.new)
// We're adding accountIds to the parentAccountIds set _after_ running
// the query
parentAccountIds.add(opp.AccountId);
if(String.isNotBlank(opp.AccountId))
// The opp's AccountId is not blank, but because we have nothing in
// parentAccountsById, we end up trying to call null.CustomField__c
// which results in an NPE
Date CustomField = parentAccountsById.get(opp.AccountId).CustomField__c;
// do stuff
The solution, as illustrated by paulK, is to use the following pattern:
- Declare/initialize a collection
- Iterate over
Trigger.new
, and add the Ids to the collection - Perform a query, using the collection of Ids gathered previously
- Iterate over
Trigger.new
again, this time doing the work you want to actually do
Again, the key part of this pattern is that we iterate twice over Trigger.new
. We need to gather the Ids we want to use in the query before we execute the query.
Nice explanation, Derek! Have an upvote!
– paulK
Nov 16 at 23:25
add a comment |
up vote
3
down vote
up vote
3
down vote
The answer by the OP does solve the problem, but I'd like to go into more detail about why it works (and why the initial attempt didn't work).
Let's take the bottom-most loop over Trigger.new
for(Opportunity opp : Trigger.new)
if(String.isNotBlank(opp.AccountId))
Date CustomField = parentAccountsById.get(opp.AccountId).CustomField__c;
// do stuff
The if
statement ensures that our Opportunity
does indeed have an AccountId
, but we can still run into a Null Pointer Exception (NPE).
Without performing some sort of null check on the map (or result), parentAccountsById.get(opp.AccountId)
can return null
.
null.<anything>
results in an NPE, because null
has no properties, variables, or methods.
Looking at OP's full first attempt (with my own comments):
trigger myTrigger on Opportunity (before insert)
// This line both declares and initializes parentAccountIds
// This allows us to use the standard set methods, but the set is empty
Set<Id> parentAccountIds = new Set<Id>();
// In this query, we haven't put anything into parentAccountIds
// This query will thus return 0 rows, but still give us our initialization
// for the map parentAccountsById.
// We can call any standard method of the Map class, but the map will contain nothing
Map<Id, Account> parentAccountsById = new Map<Id, Account>([
select Id, CustomField__c
from Account
where Id in :parentAccountIds
]);
for(Opportunity opp : Trigger.new)
// We're adding accountIds to the parentAccountIds set _after_ running
// the query
parentAccountIds.add(opp.AccountId);
if(String.isNotBlank(opp.AccountId))
// The opp's AccountId is not blank, but because we have nothing in
// parentAccountsById, we end up trying to call null.CustomField__c
// which results in an NPE
Date CustomField = parentAccountsById.get(opp.AccountId).CustomField__c;
// do stuff
The solution, as illustrated by paulK, is to use the following pattern:
- Declare/initialize a collection
- Iterate over
Trigger.new
, and add the Ids to the collection - Perform a query, using the collection of Ids gathered previously
- Iterate over
Trigger.new
again, this time doing the work you want to actually do
Again, the key part of this pattern is that we iterate twice over Trigger.new
. We need to gather the Ids we want to use in the query before we execute the query.
The answer by the OP does solve the problem, but I'd like to go into more detail about why it works (and why the initial attempt didn't work).
Let's take the bottom-most loop over Trigger.new
for(Opportunity opp : Trigger.new)
if(String.isNotBlank(opp.AccountId))
Date CustomField = parentAccountsById.get(opp.AccountId).CustomField__c;
// do stuff
The if
statement ensures that our Opportunity
does indeed have an AccountId
, but we can still run into a Null Pointer Exception (NPE).
Without performing some sort of null check on the map (or result), parentAccountsById.get(opp.AccountId)
can return null
.
null.<anything>
results in an NPE, because null
has no properties, variables, or methods.
Looking at OP's full first attempt (with my own comments):
trigger myTrigger on Opportunity (before insert)
// This line both declares and initializes parentAccountIds
// This allows us to use the standard set methods, but the set is empty
Set<Id> parentAccountIds = new Set<Id>();
// In this query, we haven't put anything into parentAccountIds
// This query will thus return 0 rows, but still give us our initialization
// for the map parentAccountsById.
// We can call any standard method of the Map class, but the map will contain nothing
Map<Id, Account> parentAccountsById = new Map<Id, Account>([
select Id, CustomField__c
from Account
where Id in :parentAccountIds
]);
for(Opportunity opp : Trigger.new)
// We're adding accountIds to the parentAccountIds set _after_ running
// the query
parentAccountIds.add(opp.AccountId);
if(String.isNotBlank(opp.AccountId))
// The opp's AccountId is not blank, but because we have nothing in
// parentAccountsById, we end up trying to call null.CustomField__c
// which results in an NPE
Date CustomField = parentAccountsById.get(opp.AccountId).CustomField__c;
// do stuff
The solution, as illustrated by paulK, is to use the following pattern:
- Declare/initialize a collection
- Iterate over
Trigger.new
, and add the Ids to the collection - Perform a query, using the collection of Ids gathered previously
- Iterate over
Trigger.new
again, this time doing the work you want to actually do
Again, the key part of this pattern is that we iterate twice over Trigger.new
. We need to gather the Ids we want to use in the query before we execute the query.
answered Nov 16 at 23:00
Derek F
18.6k31746
18.6k31746
Nice explanation, Derek! Have an upvote!
– paulK
Nov 16 at 23:25
add a comment |
Nice explanation, Derek! Have an upvote!
– paulK
Nov 16 at 23:25
Nice explanation, Derek! Have an upvote!
– paulK
Nov 16 at 23:25
Nice explanation, Derek! Have an upvote!
– paulK
Nov 16 at 23:25
add a comment |
up vote
1
down vote
Ok, found the solution...
trigger myTrigger on Opportunity (before insert)
Set<Id> parentAccountIds = new Set<Id>();
for(Opportunity newOpp : Trigger.new)
parentAccountIds.add(newOpp.AccountId);
//query fields on parent accounts and map them by Account Id
Map<Id, Account> parentAccountsById = new Map<Id, Account>([
select Id, CustomField__c
from Account
where Id in :parentAccountIds
]);
for(Opportunity opp : Trigger.new)
if(String.isNotBlank(opp.AccountId))
Date CustomField = parentAccountsById.get(opp.AccountId).CustomField__c;
// do stuff
add a comment |
up vote
1
down vote
Ok, found the solution...
trigger myTrigger on Opportunity (before insert)
Set<Id> parentAccountIds = new Set<Id>();
for(Opportunity newOpp : Trigger.new)
parentAccountIds.add(newOpp.AccountId);
//query fields on parent accounts and map them by Account Id
Map<Id, Account> parentAccountsById = new Map<Id, Account>([
select Id, CustomField__c
from Account
where Id in :parentAccountIds
]);
for(Opportunity opp : Trigger.new)
if(String.isNotBlank(opp.AccountId))
Date CustomField = parentAccountsById.get(opp.AccountId).CustomField__c;
// do stuff
add a comment |
up vote
1
down vote
up vote
1
down vote
Ok, found the solution...
trigger myTrigger on Opportunity (before insert)
Set<Id> parentAccountIds = new Set<Id>();
for(Opportunity newOpp : Trigger.new)
parentAccountIds.add(newOpp.AccountId);
//query fields on parent accounts and map them by Account Id
Map<Id, Account> parentAccountsById = new Map<Id, Account>([
select Id, CustomField__c
from Account
where Id in :parentAccountIds
]);
for(Opportunity opp : Trigger.new)
if(String.isNotBlank(opp.AccountId))
Date CustomField = parentAccountsById.get(opp.AccountId).CustomField__c;
// do stuff
Ok, found the solution...
trigger myTrigger on Opportunity (before insert)
Set<Id> parentAccountIds = new Set<Id>();
for(Opportunity newOpp : Trigger.new)
parentAccountIds.add(newOpp.AccountId);
//query fields on parent accounts and map them by Account Id
Map<Id, Account> parentAccountsById = new Map<Id, Account>([
select Id, CustomField__c
from Account
where Id in :parentAccountIds
]);
for(Opportunity opp : Trigger.new)
if(String.isNotBlank(opp.AccountId))
Date CustomField = parentAccountsById.get(opp.AccountId).CustomField__c;
// do stuff
answered Nov 16 at 22:29
paulK
487
487
add a comment |
add a comment |
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fsalesforce.stackexchange.com%2fquestions%2f239684%2fcannot-move-query-outside-of-for-loop%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown