Can Cast Child Related List to Single SObject Record – Compiler error?

This situation came up in code review and I was sure the old version should have caused a compile fail:

List<Child__c> children = new List<Child__c>();
for (Parent__c parent : parents)
{
    children.add(parent.Children__r);    // old version
    children.addAll(parent.Children__r); // new version
}

Obviously, this code blew up as soon as it was run against a parent having multiple children (or none). Now, I understand why it is allowed, since you can assign a query result to a single record or to a collection. It just seems like this behavior should not be allowed for a related list. My question is, should this code have failed to compile? Is it a compiler bug, odd quirk of the language, or something else entirely?

Answer

Yes, it’s always legal to assign a List<SObject> that came from a query into a SObject variable, and it will succeed during runtime only if there’s exactly one element. Note that child objects are always considered to have come from a query, so the following code compiles (but obviously crashes):

Account a = new Account();
Contact c = a.Contacts;

However, this is not true for native lists:

// Does not compile //
Account a = new Account[1];

Any time the compiler thinks that a particular list may have come from a query, it will allow this automatic assignment.

Obviously, since the risk for runtime errors exists, you should only use this code syntax if you are absolutely certain only one row will be returned.

This is a convenience syntax that has been around since the beginning of Apex. I’m not even sure if it’s in the documentation, and honestly, it’s more trouble than its worth most of the time; if it had been up to me, I would not allowed this syntax to exist, since it is so easy to create code that looks fine but crashes “randomly.”

Attribution
Source : Link , Question Author : Adrian Larson , Answer Author : sfdcfox

Leave a Comment