Usually if apex code attempts to access an sObject field that wasn't retrieved via SOQL I get an exception like:
System.SObjectException: SObject row was retrieved via SOQL without querying the requested field: Opportunity.Namespace_CustomField_c
This if useful, as it tells me to go back to the SOQL query that retrieved the Opportunity and add the CustomField__c field to the select.
However, I've noticed that the exception isn't always thrown. Instead the field in question is just null.
Has anyone else encountered this and have any idea why it happens?
As an example of the issue:
global with sharing class CustomController {
public Opportunity opp {get; set;}
global void method1(Id oppId) {
opp = [Select o.Id, o.Type, o.IsWon, Error_Message__c
From Opportunity o where id =:oppId limit 1 FOR UPDATE];
// Setting this field appears prevents any further SObjectExceptions
// NB: This was added after the question was originally asked to highlight the issue.
opp.Error_Message__c = '';
System.debug('opp.CustomField__c: ' + opp.CustomField__c);
method2(opp);
}
public void method2(Opportunity opp) {
if(opp.CustomField__c != null) {
System.debug('DoStuff');
}
}
}
- Create an instance of a custom controller class
CustomController
- Invoke the public method
method1
on the above class that takes an Opportunity Id - The public method
method1
runs a SOQL query to retrieve the Opportunity and a number of fields, but not CustomField__c. The retrieved Opportunity is assigned to a public propertyopp
on the controller. - The Opportunity property
opp
is passed as a parameter to another method in the custom controller class. (I'm aware that this isn't necessary as the method would otherwise be able to see the value via the public property) - The method
method2
that received the Opportunity checks if the custom field is not null before attempting to use the value to do some other updates.
If I create an instance of the custom controller in anonymous apex and invoke the method from point 2 no SObjectException is thrown and the CustomField__c value is always null.
If I create an instance of the custom controller in anonymous apex, run the same SOQL query and pass the resulting Opportunity directly to the method in point 4 I get the expected SObjectException.
Attribution to: Daniel Ballinger
Possible Suggestion/Solution #1
I cannot seem to reproduce what you've described, I get the sObject not retrieved error for Case 1 too!
The only caveat would be that since sObjects are passed by reference, hopefully there isn't a sneaky bit of assignment which is setting the value of CustomField1 somewhere in the foodchain.
If there is an assignment of value then it wouldn't throw the exception for any subsequent access. (Even though it wasn't initially retrieved as part of the soql)
As a simplified example, this will throw the SObjectException (assuming you have at least one Opportunity):
Opportunity opp = [select Id, StageName From Opportunity limit 1];
System.debug(opp.Probability);
And this will not (opp.Probablity will be null):
Opportunity opp = [select Id, StageName From Opportunity limit 1];
opp.StageName = 'foo';
System.debug(opp.Probability);
Attribution to: techtrekker
Possible Suggestion/Solution #2
You could consider the sObjectSelector pattern that we use which assures us that whenever we select records for a particular sObject type, the fields of interest to us are always included.
OpportunitySelector.cls extends sObjectSelector.cls and makes use of StringBuilder.cls
Attribution to: Stephen Willcock
This content is remixed from stackoverflow or stackexchange. Please visit https://salesforce.stackexchange.com/questions/3648