9

I'm currently querying the records of a custom object, including some related child records. Unfortunately the parent object is unknown, so the returned results from the query is a list of SObjects.
Is it possible to either dynamically type caste the returned results, or access the child records via an SObject?

i.e. The following code returns a list of Accounts with child Contacts included.

String query = 'SELECT Id, Name, (SELECT Id, Name FROM Contacts) FROM Account LIMIT 2';

List<Account> listOfObjects = Database.query(query);

for(Account singleObject : listOfObjects) {
    system.debug(singleObject);
    for(Contact childContact : singleObject.Contacts) {
        system.debug('Contact Name: ' + childContact.Name);
    }
}

If you run this in execute anonymous it works as expected.
If however I change it from an Account to a generic SObject I get the error Field expression not allowed for generic SObject on the for(Contact childContact : singleObject.Contacts) line.

i.e.

String query = 'SELECT Id, Name, (SELECT Id, Name FROM Contacts) FROM Account LIMIT 2';

// Change from Account to SObject
List<SObject> listOfObjects = Database.query(query);

for(SObject singleObject : listOfObjects) {
    system.debug(singleObject);
    for(Contact childContact : singleObject.Contacts) {
        system.debug('Contact Name: ' + childContact.Name);
    }
}

Really what I'm trying to achieve is to process the child records with a single SOQL statement, but I don't think I can do this.

I can't caste with a concrete object because I don't know what type of object to caste it to until runtime.

I'm thinking I either need to:

  1. somehow dynamically caste the generic SObject to a concrete object
  2. find a way to access the child records on a generic SObject.
  3. Do a separate query on the child table
  4. have a whole bunch of if statements so that I can caste directly to the types of objects this may be relevant for

Has anyone come across this before and has a solution?

NOTE: in my proper code the objects used are custom object. The examples provided here are so that it can work for anyone that tries it.

  • 1
    Thanks for using standard objects in your example by the way. – martin Sep 2 '15 at 8:36
  • 2
    yeah, it's a lot easier if the code will work in anyone's execute anonymous window. – Nick Cook Sep 2 '15 at 8:44
8

There are sufficient methods on the SObject base type to write code that isn't tied at all to specific SObject types. You can get and set primitive field values and navigate across both parent and child relationships. (The only thing I have noticed missing from the API is the ability to add errors to specific SObject fields; there is only the ability to add an error to the overall SObject via SObject.addError.)

In this example you could use this code:

String query = 'SELECT Id, Name, (SELECT Id, Name FROM Contacts) FROM Account LIMIT 2';
List<SObject> parents = Database.query(query);
for(SObject parent : parents) {
    for(SObject child : parent.getSObjects('Contacts')) {
        system.debug('Child=' + child);
    }
}

The describe calls also allow you to discover field names such as the "Contacts" that I have hard coded if you want to write completely metadata driven code. Also note that when you have an ID value you can get the SObject type using Id.getSObjectType.

1

If you cast the sObject as an Account, you should be able to access the list of Contacts:

for(Contact childContact : ((Account) singleObject).Contacts) {
  • Thanks. That works in this example, however the type of object I need to caste it to is unknown and you can't use a Account.SObjectType statement for casting. I'll update my question to clarify. – Nick Cook Sep 2 '15 at 8:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.