Take the 2-minute tour ×
Salesforce Stack Exchange is a question and answer site for Salesforce administrators, implementation experts, developers and anybody in-between. It's 100% free, no registration required.

I am trying to modify a list of sobjects that I get from a subquery but it appears that adds to the list are simply silently ignored. sample code:

Account acc = [select ID, (select ID from Contacts limit 1) from Account limit 1];
Integer consize = acc.contacts.size();
acc.contacts.add(new Contact(lastname='test'));
system.assertequals(consize+1,acc.contacts.size());

Is this expected behaviour? I might be misremembering but I could swear I've done this in the past.

UPDATE: Setting acc.contacts directly will also not work as you get the following error:

Field is not writeable: Contacts

If you assign acc.contacts to a list you can then work with the list as normal but this is not ideal for my use case as I have a function that I want to return a list of sobjects with 1-n subqueries.

UPDATE 2: It appears that you can modify the properties of the sobjects in the list, just not the list itself.

Account acc = [select ID, (select ID from Contacts limit 1) from Account limit 1];
list<Contact> con1 = acc.contacts;
con1.get(0).lastname = 'TEST';
system.assertequals('TEST',acc.contacts.get(0).lastname);

list<Contact> con2 = acc.contacts.clone();
con1.get(0).lastname = 'TEST2';
system.assertequals('TEST2',acc.contacts.get(0).lastname);
share|improve this question
2  
System.assert(acc.contacts === acc.contacts); fails, so you never have access to the actual underlying list reference. I don't see it documented anywhere that a cloned copy is what to expect for a child list, but it would be consistent with trying to keep the list from not being writable. Likewise acc.contacts.remove has no effect. –  Peter Knolle Jan 28 '13 at 4:06
    
This is a real curiosity and not what I expected. Even if I pass the list to a new variable, it is not writable. That being said, I've also never tried it this way, I always associate new related records by assigning an id to the related ID field. Maybe this is in place to prevent someone adding the contact but not assigning the AccountId value? –  Peter Jan 28 '13 at 11:20
    
@PeterKnolle didn't even know there was an exact equality operator in apex. If you run this in dev console with apex FINEST you can see that everytime you assign acc.contacts to a list it is creating a new reference (different memory address) so it definitely appears to be cloning it behind the scenes. –  Greg Grinberg Jan 28 '13 at 16:48
    
@PeterKnolle What is really odd is that even though it gives a new memory address each time you assign the list every object in the list still has the same references. (code above) –  Greg Grinberg Jan 28 '13 at 16:52
    
@PeterKnolle I think we've basically proved that it is making a clone of the list behind the scenes whenever you get the sub-query. You can go ahead and post that as the answer if you'd like. –  Greg Grinberg Jan 28 '13 at 17:16
add comment

2 Answers

up vote 2 down vote accepted

System.assert(acc.contacts === acc.contacts); fails, so you never have access to the actual underlying list reference. Each time there is a call to acc.contacts a different List<Contact> is created and returned.

I don't see it documented anywhere that a cloned copy is what to expect for a child list, but it would be consistent with trying to keep the list from not being writable. Likewise acc.contacts.remove has no effect.

share|improve this answer
add comment

That's pretty strange that modifications to the list aren't stored by reference, kudos for figuring out that it's regenerated each time you access it. Can't think of any good reason why they'd do it that way.

You'll want to work with them as a list created from your query object. I don't know your exact use case, but keeping them in the account.contacts list isn't going to be useful for updating even if you could modify the list. Changes made to non-query objects (subqueries and parent objects) are ignored in update calls (i.e. account.owner.lastName = 'asdf' would be stored in memory but not committed if you updated the acccount).

If you're trying to keep things grouped for display this might work well for you.

public Class AccountGroup {
  public Account account { get; set; }
  public List<Contact> contacts { get; set; }

  public AccountGroup(Account account) {
    this.account = account;
    contacts = account.contacts;
  }
}
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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