Friday, June 6, 2014

apex soql subselect weirdness with "with sharing"

I had some code similar to the following:

Public with sharing class MyClass{
...
    ParentObject__c[] pos = [select Id, (select MasterDetail_2__c from ChildObjects__r)
        from ParentObject__c];
...
   Set MasterDetail_1s = new Set();
    for(ParentObject__c po:pos){
        for(ChildObject__co: po.ChildObjects__r){
            MasterDetail_1s.add(co.MasterDetail_1__c);
        }
    }
...
}

But I was not getting any child records back in the select. Infuriatingly, running the query in the Developer Console Query Editor/Force.com IDE Schema/Force.com Explorer returned the expected results.

While checking that the problem wasn't related to permissions, I changed "with sharing" to "without sharing" and then immediately the following error was reported:

SObject row was retrieved via SOQL without querying the requested field: ChildObject__c.MasterDetail__1__c

With this simplified version of the code it's obvious there is a problem: ChildObject__c.MasterDetail_1__c is used without having been queried. However this error wasn't being reported when the class was declared as "with sharing".

In summary: if subselects are not behaving, "with sharing" may be hiding the errors. Switch to "without sharing" for debug purposes, fix the code and switch back again.

Edit: it actually seems to be more complicated than this - the code stopped working again even with "without sharing". The actual code had something more like

MasterDetail_1s.add(String.valueOf(co.MasterDetail_1__c));

which appeared to cause a problem, but again no exception was raised. I avoided this by removing the explicit conversion.